From ac8cd5368db83cced9bc049ceb50c21cb8a4f743 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 12 Mar 2024 10:44:53 +0800 Subject: refactor: use ml_get_buf_len() in API code (#27825) --- src/nvim/lua/executor.c | 4 ++-- src/nvim/lua/stdlib.c | 6 +++--- src/nvim/lua/treesitter.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1a9bd026b5..08677b77b0 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1767,7 +1767,7 @@ void ex_luado(exarg_T *const eap) lua_pushvalue(lstate, -1); const char *const old_line = ml_get_buf(curbuf, l); // Get length of old_line here as calling Lua code may free it. - const size_t old_line_len = strlen(old_line); + const colnr_T old_line_len = ml_get_buf_len(curbuf, l); lua_pushstring(lstate, old_line); lua_pushnumber(lstate, (lua_Number)l); if (nlua_pcall(lstate, 2, 1)) { @@ -1791,7 +1791,7 @@ void ex_luado(exarg_T *const eap) } } ml_replace(l, new_line_transformed, false); - inserted_bytes(l, 0, (int)old_line_len, (int)new_line_len); + inserted_bytes(l, 0, old_line_len, (int)new_line_len); } lua_pop(lstate, 1); } diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 8f58fd1a1a..a5262efcfa 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -107,15 +107,15 @@ static int regex_match_line(lua_State *lstate) } char *line = ml_get_buf(buf, rownr + 1); - size_t len = strlen(line); + colnr_T len = ml_get_buf_len(buf, rownr + 1); - if (start < 0 || (size_t)start > len) { + if (start < 0 || start > len) { return luaL_error(lstate, "invalid start"); } char save = NUL; if (end >= 0) { - if ((size_t)end > len || end < start) { + if (end > len || end < start) { return luaL_error(lstate, "invalid end"); } save = line[end]; diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 25a753b179..6d6ef6c7b9 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -371,7 +371,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position return ""; } char *line = ml_get_buf(bp, (linenr_T)position.row + 1); - size_t len = strlen(line); + size_t len = (size_t)ml_get_buf_len(bp, (linenr_T)position.row + 1); if (position.column > len) { *bytes_read = 0; return ""; -- cgit From 08fc1ebbaa49e3110b65bddeed28d2e61a96f5d9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 11 Mar 2024 13:19:49 +0100 Subject: fix(api/buffer): fix handling of viewport of non-current buffer A lot of functions in move.c only worked for curwin, alternatively took a `wp` arg but still only work if that happens to be curwin. Refactor those that are needed for update_topline(wp) to work for any window. fixes #27723 fixes #27720 --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 08677b77b0..78c746d169 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1797,7 +1797,7 @@ void ex_luado(exarg_T *const eap) } lua_pop(lstate, 1); - check_cursor(); + check_cursor(curwin); redraw_curbuf_later(UPD_NOT_VALID); } -- cgit From aca2048bcd57937ea1c7b7f0325f25d5b82588db Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 18 Mar 2024 23:19:01 +0000 Subject: refactor(treesitter): redesign query iterating Problem: `TSNode:_rawquery()` is complicated, has known issues and the Lua and C code is awkwardly coupled (see logic with `active`). Solution: - Add `TSQueryCursor` and `TSQueryMatch` bindings. - Replace `TSNode:_rawquery()` with `TSQueryCursor:next_capture()` and `TSQueryCursor:next_match()` - Do more stuff in Lua - API for `Query:iter_captures()` and `Query:iter_matches()` remains the same. - `treesitter.c` no longer contains any logic related to predicates. - Add `match_limit` option to `iter_matches()`. Default is still 256. --- src/nvim/lua/executor.c | 3 + src/nvim/lua/treesitter.c | 265 ++++++++++++++++++++++------------------------ 2 files changed, 129 insertions(+), 139 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 78c746d169..d5d35c5295 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1909,6 +1909,9 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, tslua_push_parser); lua_setfield(lstate, -2, "_create_ts_parser"); + lua_pushcfunction(lstate, tslua_push_querycursor); + lua_setfield(lstate, -2, "_create_ts_querycursor"); + lua_pushcfunction(lstate, tslua_add_language); lua_setfield(lstate, -2, "_ts_add_language"); diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 6d6ef6c7b9..2d44e485cb 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -33,14 +33,9 @@ #define TS_META_NODE "treesitter_node" #define TS_META_QUERY "treesitter_query" #define TS_META_QUERYCURSOR "treesitter_querycursor" +#define TS_META_QUERYMATCH "treesitter_querymatch" #define TS_META_TREECURSOR "treesitter_treecursor" -typedef struct { - TSQueryCursor *cursor; - int predicated_match; - int max_match_id; -} TSLua_cursor; - typedef struct { LuaRef cb; lua_State *lstate; @@ -108,7 +103,6 @@ static struct luaL_Reg node_meta[] = { { "named_descendant_for_range", node_named_descendant_for_range }, { "parent", node_parent }, { "iter_children", node_iter_children }, - { "_rawquery", node_rawquery }, { "next_sibling", node_next_sibling }, { "prev_sibling", node_prev_sibling }, { "next_named_sibling", node_next_named_sibling }, @@ -130,18 +124,27 @@ static struct luaL_Reg query_meta[] = { { NULL, NULL } }; -// cursors are not exposed, but still needs garbage collection +// TSQueryCursor static struct luaL_Reg querycursor_meta[] = { + { "remove_match", querycursor_remove_match }, + { "next_capture", querycursor_next_capture }, + { "next_match", querycursor_next_match }, { "__gc", querycursor_gc }, { NULL, NULL } }; +// TSQueryMatch +static struct luaL_Reg querymatch_meta[] = { + { "info", querymatch_info }, + { "captures", querymatch_captures }, + { NULL, NULL } +}; + static struct luaL_Reg treecursor_meta[] = { { "__gc", treecursor_gc }, { NULL, NULL } }; -static kvec_t(TSQueryCursor *) cursors = KV_INITIAL_VALUE; static PMap(cstr_t) langs = MAP_INIT; static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) @@ -166,6 +169,7 @@ void tslua_init(lua_State *L) build_meta(L, TS_META_NODE, node_meta); build_meta(L, TS_META_QUERY, query_meta); build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); + build_meta(L, TS_META_QUERYMATCH, querymatch_meta); build_meta(L, TS_META_TREECURSOR, treecursor_meta); ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); @@ -1361,173 +1365,156 @@ static int node_equal(lua_State *L) return 1; } -/// assumes the match table being on top of the stack -static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx) -{ - // [match] - for (size_t i = 0; i < match->capture_count; i++) { - lua_rawgeti(L, -1, (int)match->captures[i].index + 1); // [match, captures] - if (lua_isnil(L, -1)) { // [match, nil] - lua_pop(L, 1); // [match] - lua_createtable(L, 1, 0); // [match, captures] - } - push_node(L, match->captures[i].node, nodeidx); // [match, captures, node] - lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1); // [match, captures] - lua_rawseti(L, -2, (int)match->captures[i].index + 1); // [match] - } -} - -static int query_next_match(lua_State *L) -{ - TSLua_cursor *ud = lua_touserdata(L, lua_upvalueindex(1)); - TSQueryCursor *cursor = ud->cursor; - - TSQuery *query = query_check(L, lua_upvalueindex(3)); - TSQueryMatch match; - if (ts_query_cursor_next_match(cursor, &match)) { - lua_pushinteger(L, match.pattern_index + 1); // [index] - lua_createtable(L, (int)ts_query_capture_count(query), 0); // [index, match] - set_match(L, &match, lua_upvalueindex(2)); - return 2; - } - return 0; -} - -static int query_next_capture(lua_State *L) -{ - // Upvalues are: - // [ cursor, node, query, current_match ] - TSLua_cursor *ud = lua_touserdata(L, lua_upvalueindex(1)); - TSQueryCursor *cursor = ud->cursor; - - TSQuery *query = query_check(L, lua_upvalueindex(3)); - - if (ud->predicated_match > -1) { - lua_getfield(L, lua_upvalueindex(4), "active"); - bool active = lua_toboolean(L, -1); - lua_pop(L, 1); - if (!active) { - ts_query_cursor_remove_match(cursor, (uint32_t)ud->predicated_match); - } - ud->predicated_match = -1; - } - - TSQueryMatch match; - uint32_t capture_index; - if (ts_query_cursor_next_capture(cursor, &match, &capture_index)) { - TSQueryCapture capture = match.captures[capture_index]; - - // TODO(vigoux): handle capture quantifiers here - lua_pushinteger(L, capture.index + 1); // [index] - push_node(L, capture.node, lua_upvalueindex(2)); // [index, node] - - // Now check if we need to run the predicates - uint32_t n_pred; - ts_query_predicates_for_pattern(query, match.pattern_index, &n_pred); - - if (n_pred > 0 && (ud->max_match_id < (int)match.id)) { - ud->max_match_id = (int)match.id; - - // Create a new cleared match table - lua_createtable(L, (int)ts_query_capture_count(query), 2); // [index, node, match] - set_match(L, &match, lua_upvalueindex(2)); - lua_pushinteger(L, match.pattern_index + 1); - lua_setfield(L, -2, "pattern"); - - if (match.capture_count > 1) { - ud->predicated_match = (int)match.id; - lua_pushboolean(L, false); - lua_setfield(L, -2, "active"); - } - - // Set current_match to the new match - lua_replace(L, lua_upvalueindex(4)); // [index, node] - lua_pushvalue(L, lua_upvalueindex(4)); // [index, node, match] - return 3; - } - return 2; - } - return 0; -} - -static int node_rawquery(lua_State *L) +int tslua_push_querycursor(lua_State *L) { TSNode node; if (!node_check(L, 1, &node)) { - return 0; + return luaL_error(L, "TSNode expected"); } - TSQuery *query = query_check(L, 2); - TSQueryCursor *cursor; - if (kv_size(cursors) > 0) { - cursor = kv_pop(cursors); - } else { - cursor = ts_query_cursor_new(); + TSQuery *query = query_check(L, 2); + if (!query) { + return luaL_error(L, "TSQuery expected"); } - ts_query_cursor_set_max_start_depth(cursor, UINT32_MAX); - ts_query_cursor_set_match_limit(cursor, 256); + TSQueryCursor *cursor = ts_query_cursor_new(); ts_query_cursor_exec(cursor, query, node); - bool captures = lua_toboolean(L, 3); - - if (lua_gettop(L) >= 4) { - uint32_t start = (uint32_t)luaL_checkinteger(L, 4); - uint32_t end = lua_gettop(L) >= 5 ? (uint32_t)luaL_checkinteger(L, 5) : MAXLNUM; + if (lua_gettop(L) >= 3) { + uint32_t start = (uint32_t)luaL_checkinteger(L, 3); + uint32_t end = lua_gettop(L) >= 4 ? (uint32_t)luaL_checkinteger(L, 4) : MAXLNUM; ts_query_cursor_set_point_range(cursor, (TSPoint){ start, 0 }, (TSPoint){ end, 0 }); } - if (lua_gettop(L) >= 6 && !lua_isnil(L, 6)) { - if (!lua_istable(L, 6)) { + if (lua_gettop(L) >= 5 && !lua_isnil(L, 5)) { + if (!lua_istable(L, 5)) { return luaL_error(L, "table expected"); } - lua_pushnil(L); - // stack: [dict, ..., nil] - while (lua_next(L, 6)) { - // stack: [dict, ..., key, value] + lua_pushnil(L); // [dict, ..., nil] + while (lua_next(L, 5)) { + // [dict, ..., key, value] if (lua_type(L, -2) == LUA_TSTRING) { char *k = (char *)lua_tostring(L, -2); if (strequal("max_start_depth", k)) { uint32_t max_start_depth = (uint32_t)lua_tointeger(L, -1); ts_query_cursor_set_max_start_depth(cursor, max_start_depth); + } else if (strequal("match_limit", k)) { + uint32_t match_limit = (uint32_t)lua_tointeger(L, -1); + ts_query_cursor_set_match_limit(cursor, match_limit); } } - lua_pop(L, 1); // pop the value; lua_next will pop the key. - // stack: [dict, ..., key] + // pop the value; lua_next will pop the key. + lua_pop(L, 1); // [dict, ..., key] } } - TSLua_cursor *ud = lua_newuserdata(L, sizeof(*ud)); // [udata] - ud->cursor = cursor; - ud->predicated_match = -1; - ud->max_match_id = -1; + TSQueryCursor **ud = lua_newuserdata(L, sizeof(*ud)); // [node, query, ..., udata] + *ud = cursor; + lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYCURSOR); // [node, query, ..., udata, meta] + lua_setmetatable(L, -2); // [node, query, ..., udata] + + // Copy the fenv which contains the nodes tree. + lua_getfenv(L, 1); // [udata, reftable] + lua_setfenv(L, -2); // [udata] - lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYCURSOR); + return 1; +} + +static int querycursor_remove_match(lua_State *L) +{ + TSQueryCursor *cursor = querycursor_check(L, 1); + uint32_t match_id = (uint32_t)luaL_checkinteger(L, 2); + ts_query_cursor_remove_match(cursor, match_id); + return 0; +} + +static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) +{ + TSQueryMatch *ud = lua_newuserdata(L, sizeof(TSQueryMatch)); // [udata] + *ud = *match; + lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYMATCH); // [udata, meta] lua_setmetatable(L, -2); // [udata] - lua_pushvalue(L, 1); // [udata, node] - // include query separately, as to keep a ref to it for gc - lua_pushvalue(L, 2); // [udata, node, query] + // Copy the fenv which contains the nodes tree. + lua_getfenv(L, uindex); // [udata, reftable] + lua_setfenv(L, -2); // [udata] +} + +static int querycursor_next_capture(lua_State *L) +{ + TSQueryCursor *cursor = querycursor_check(L, 1); - if (captures) { - // placeholder for match state - lua_createtable(L, (int)ts_query_capture_count(query), 2); // [u, n, q, match] - lua_pushcclosure(L, query_next_capture, 4); // [closure] - } else { - lua_pushcclosure(L, query_next_match, 3); // [closure] + TSQueryMatch match; + uint32_t capture_index; + if (!ts_query_cursor_next_capture(cursor, &match, &capture_index)) { + return 0; } + TSQueryCapture capture = match.captures[capture_index]; + + // Handle capture quantifiers here + lua_pushinteger(L, capture.index + 1); // [index] + push_node(L, capture.node, 1); // [index, node] + push_querymatch(L, &match, 1); + + return 3; +} + +static int querycursor_next_match(lua_State *L) +{ + TSQueryCursor *cursor = querycursor_check(L, 1); + + TSQueryMatch match; + if (!ts_query_cursor_next_match(cursor, &match)) { + return 0; + } + + push_querymatch(L, &match, 1); + return 1; } +static TSQueryCursor *querycursor_check(lua_State *L, int index) +{ + TSQueryCursor **ud = luaL_checkudata(L, index, TS_META_QUERYCURSOR); + return *ud; +} + static int querycursor_gc(lua_State *L) { - TSLua_cursor *ud = luaL_checkudata(L, 1, TS_META_QUERYCURSOR); - kv_push(cursors, ud->cursor); - ud->cursor = NULL; + TSQueryCursor *cursor = querycursor_check(L, 1); + ts_query_cursor_delete(cursor); return 0; } +static int querymatch_info(lua_State *L) +{ + TSQueryMatch *ud = luaL_checkudata(L, 1, TS_META_QUERYMATCH); + lua_pushinteger(L, ud->id); + lua_pushinteger(L, ud->pattern_index + 1); + return 2; +} + +static int querymatch_captures(lua_State *L) +{ + TSQueryMatch *match = luaL_checkudata(L, 1, TS_META_QUERYMATCH); + lua_newtable(L); // [match, nodes, captures] + for (size_t i = 0; i < match->capture_count; i++) { + TSQueryCapture capture = match->captures[i]; + int index = (int)capture.index + 1; + + lua_rawgeti(L, -1, index); // [match, node, captures] + if (lua_isnil(L, -1)) { // [match, node, captures, nil] + lua_pop(L, 1); // [match, node, captures] + lua_newtable(L); // [match, node, captures, nodes] + } + push_node(L, capture.node, 1); // [match, node, captures, nodes, node] + lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1); // [match, node, captures, nodes] + lua_rawseti(L, -2, index); // [match, node, captures] + } + return 1; +} + // Query methods int tslua_parse_query(lua_State *L) @@ -1638,7 +1625,7 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err static TSQuery *query_check(lua_State *L, int index) { TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY); - return *ud; + return ud ? *ud : NULL; } static int query_gc(lua_State *L) -- cgit From aca6c930025e191f22cfb541b01cb89093b9b809 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 19 Mar 2024 14:25:54 +0000 Subject: refactor(treesitter): simplify argument checks for userdata --- src/nvim/lua/treesitter.c | 418 +++++++++++++++------------------------------- 1 file changed, 136 insertions(+), 282 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 2d44e485cb..0cf1ad2833 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -258,14 +258,19 @@ int tslua_remove_lang(lua_State *L) return 1; } -int tslua_inspect_lang(lua_State *L) +static TSLanguage *lang_check(lua_State *L, int index) { - const char *lang_name = luaL_checkstring(L, 1); - + const char *lang_name = luaL_checkstring(L, index); TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { - return luaL_error(L, "no such language: %s", lang_name); + luaL_error(L, "no such language: %s", lang_name); } + return lang; +} + +int tslua_inspect_lang(lua_State *L) +{ + TSLanguage *lang = lang_check(L, 1); lua_createtable(L, 0, 2); // [retval] @@ -308,19 +313,14 @@ int tslua_inspect_lang(lua_State *L) int tslua_push_parser(lua_State *L) { - // Gather language name - const char *lang_name = luaL_checkstring(L, 1); - - TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); - if (!lang) { - return luaL_error(L, "no such language: %s", lang_name); - } + TSLanguage *lang = lang_check(L, 1); TSParser **parser = lua_newuserdata(L, sizeof(TSParser *)); *parser = ts_parser_new(); if (!ts_parser_set_language(*parser, lang)) { ts_parser_delete(*parser); + const char *lang_name = luaL_checkstring(L, 1); return luaL_error(L, "Failed to load language : %s", lang_name); } @@ -329,9 +329,13 @@ int tslua_push_parser(lua_State *L) return 1; } -static TSParser **parser_check(lua_State *L, uint16_t index) +static TSParser *parser_check(lua_State *L, uint16_t index) { - return luaL_checkudata(L, index, TS_META_PARSER); + TSParser **ud = luaL_checkudata(L, index, TS_META_PARSER); + if (!ud || !(*ud)) { + luaL_argerror(L, index, "TSParser expected"); + } + return *ud; } static void logger_gc(TSLogger logger) @@ -347,13 +351,9 @@ static void logger_gc(TSLogger logger) static int parser_gc(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } - - logger_gc(ts_parser_logger(*p)); - ts_parser_delete(*p); + TSParser *p = parser_check(L, 1); + logger_gc(ts_parser_logger(p)); + ts_parser_delete(p); return 0; } @@ -426,11 +426,7 @@ static void push_ranges(lua_State *L, const TSRange *ranges, const size_t length static int parser_parse(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p || !(*p)) { - return 0; - } - + TSParser *p = parser_check(L, 1); TSTree *old_tree = NULL; if (!lua_isnil(L, 2)) { TSLuaTree *ud = tree_check(L, 2); @@ -449,7 +445,7 @@ static int parser_parse(lua_State *L) switch (lua_type(L, 3)) { case LUA_TSTRING: str = lua_tolstring(L, 3, &len); - new_tree = ts_parser_parse_string(*p, old_tree, str, (uint32_t)len); + new_tree = ts_parser_parse_string(p, old_tree, str, (uint32_t)len); break; case LUA_TNUMBER: @@ -465,7 +461,7 @@ static int parser_parse(lua_State *L) } input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 }; - new_tree = ts_parser_parse(*p, old_tree, input); + new_tree = ts_parser_parse(p, old_tree, input); break; @@ -496,21 +492,14 @@ static int parser_parse(lua_State *L) static int parser_reset(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (p && *p) { - ts_parser_reset(*p); - } - + TSParser *p = parser_check(L, 1); + ts_parser_reset(p); return 0; } static int tree_copy(lua_State *L) { TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } - TSTree *copy = ts_tree_copy(ud->tree); push_tree(L, copy); // [tree] @@ -525,9 +514,6 @@ static int tree_edit(lua_State *L) } TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } uint32_t start_byte = (uint32_t)luaL_checkint(L, 2); uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3); @@ -547,9 +533,6 @@ static int tree_edit(lua_State *L) static int tree_get_ranges(lua_State *L) { TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); @@ -562,6 +545,11 @@ static int tree_get_ranges(lua_State *L) return 1; } +static void range_err(lua_State *L) +{ + luaL_error(L, "Ranges can only be made from 6 element long tables or nodes."); +} + // Use the top of the stack (without popping it) to create a TSRange, it can be // either a lua table or a TSNode static void range_from_lua(lua_State *L, TSRange *range) @@ -571,7 +559,7 @@ static void range_from_lua(lua_State *L, TSRange *range) if (lua_istable(L, -1)) { // should be a table of 6 elements if (lua_objlen(L, -1) != 6) { - goto error; + range_err(L); } lua_rawgeti(L, -1, 1); // [ range, start_row] @@ -610,7 +598,7 @@ static void range_from_lua(lua_State *L, TSRange *range) .start_byte = start_byte, .end_byte = end_byte, }; - } else if (node_check(L, -1, &node)) { + } else if (node_check2(L, -1, &node)) { *range = (TSRange) { .start_point = ts_node_start_point(node), .end_point = ts_node_end_point(node), @@ -618,29 +606,20 @@ static void range_from_lua(lua_State *L, TSRange *range) .end_byte = ts_node_end_byte(node) }; } else { - goto error; + range_err(L); } - return; -error: - luaL_error(L, - "Ranges can only be made from 6 element long tables or nodes."); } static int parser_set_ranges(lua_State *L) { if (lua_gettop(L) < 2) { - return luaL_error(L, - "not enough args to parser:set_included_ranges()"); + return luaL_error(L, "not enough args to parser:set_included_ranges()"); } - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); if (!lua_istable(L, 2)) { - return luaL_error(L, - "argument for parser:set_included_ranges() should be a table."); + return luaL_argerror(L, 2, "table expected."); } size_t tbl_len = lua_objlen(L, 2); @@ -654,7 +633,7 @@ static int parser_set_ranges(lua_State *L) } // This memcpies ranges, thus we can free it afterwards - ts_parser_set_included_ranges(*p, ranges, (uint32_t)tbl_len); + ts_parser_set_included_ranges(p, ranges, (uint32_t)tbl_len); xfree(ranges); return 0; @@ -662,15 +641,12 @@ static int parser_set_ranges(lua_State *L) static int parser_get_ranges(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); uint32_t len; - const TSRange *ranges = ts_parser_included_ranges(*p, &len); + const TSRange *ranges = ts_parser_included_ranges(p, &len); push_ranges(L, ranges, len, include_bytes); return 1; @@ -678,28 +654,21 @@ static int parser_get_ranges(lua_State *L) static int parser_set_timeout(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); if (lua_gettop(L) < 2) { luaL_error(L, "integer expected"); } uint32_t timeout = (uint32_t)luaL_checkinteger(L, 2); - ts_parser_set_timeout_micros(*p, timeout); + ts_parser_set_timeout_micros(p, timeout); return 0; } static int parser_get_timeout(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } - - lua_pushinteger(L, (lua_Integer)ts_parser_timeout_micros(*p)); + TSParser *p = parser_check(L, 1); + lua_pushinteger(L, (lua_Integer)ts_parser_timeout_micros(p)); return 1; } @@ -723,10 +692,7 @@ static void logger_cb(void *payload, TSLogType logtype, const char *s) static int parser_set_logger(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); if (!lua_isboolean(L, 2)) { return luaL_argerror(L, 2, "boolean expected"); @@ -756,18 +722,14 @@ static int parser_set_logger(lua_State *L) .log = logger_cb }; - ts_parser_set_logger(*p, logger); + ts_parser_set_logger(p, logger); return 0; } static int parser_get_logger(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } - - TSLogger logger = ts_parser_logger(*p); + TSParser *p = parser_check(L, 1); + TSLogger logger = ts_parser_logger(p); if (logger.log) { TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)logger.payload; lua_rawgeti(L, LUA_REGISTRYINDEX, opts->cb); @@ -811,15 +773,16 @@ static void push_tree(lua_State *L, TSTree *tree) static TSLuaTree *tree_check(lua_State *L, int index) { TSLuaTree *ud = luaL_checkudata(L, index, TS_META_TREE); + if (!ud) { + luaL_argerror(L, index, "TSTree expected"); + } return ud; } static int tree_gc(lua_State *L) { TSLuaTree *ud = tree_check(L, 1); - if (ud) { - ts_tree_delete(ud->tree); - } + ts_tree_delete(ud->tree); return 0; } @@ -832,9 +795,6 @@ static int tree_tostring(lua_State *L) static int tree_root(lua_State *L) { TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } TSNode root = ts_tree_root_node(ud->tree); push_node(L, root, 1); return 1; @@ -864,7 +824,7 @@ static void push_node(lua_State *L, TSNode node, int uindex) lua_setfenv(L, -2); // [udata] } -static bool node_check(lua_State *L, int index, TSNode *res) +static bool node_check2(lua_State *L, int index, TSNode *res) { TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); if (ud) { @@ -874,12 +834,18 @@ static bool node_check(lua_State *L, int index, TSNode *res) return false; } -static int node_tostring(lua_State *L) +static TSNode node_check(lua_State *L, int index) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; + TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); + if (!ud) { + luaL_argerror(L, index, "TSNode expected"); } + return *ud; +} + +static int node_tostring(lua_State *L) +{ + TSNode node = node_check(L, 1); lua_pushstring(L, ""); @@ -889,37 +855,22 @@ static int node_tostring(lua_State *L) static int node_eq(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - - TSNode node2; - if (!node_check(L, 2, &node2)) { - return 0; - } - + TSNode node = node_check(L, 1); + TSNode node2 = node_check(L, 2); lua_pushboolean(L, ts_node_eq(node, node2)); return 1; } static int node_id(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + TSNode node = node_check(L, 1); lua_pushlstring(L, (const char *)&node.id, sizeof node.id); return 1; } static int node_range(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); @@ -945,10 +896,7 @@ static int node_range(lua_State *L) static int node_start(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint start = ts_node_start_point(node); uint32_t start_byte = ts_node_start_byte(node); lua_pushinteger(L, start.row); @@ -959,10 +907,7 @@ static int node_start(lua_State *L) static int node_end(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint end = ts_node_end_point(node); uint32_t end_byte = ts_node_end_byte(node); lua_pushinteger(L, end.row); @@ -973,10 +918,7 @@ static int node_end(lua_State *L) static int node_child_count(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t count = ts_node_child_count(node); lua_pushinteger(L, count); return 1; @@ -984,10 +926,7 @@ static int node_child_count(lua_State *L) static int node_named_child_count(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t count = ts_node_named_child_count(node); lua_pushinteger(L, count); return 1; @@ -995,20 +934,14 @@ static int node_named_child_count(lua_State *L) static int node_type(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushstring(L, ts_node_type(node)); return 1; } static int node_symbol(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSSymbol symbol = ts_node_symbol(node); lua_pushinteger(L, symbol); return 1; @@ -1016,10 +949,7 @@ static int node_symbol(lua_State *L) static int node_field(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); size_t name_len; const char *field_name = luaL_checklstring(L, 2, &name_len); @@ -1046,20 +976,14 @@ static int node_field(lua_State *L) static int node_named(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_is_named(node)); return 1; } static int node_sexpr(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); char *allocated = ts_node_string(node); lua_pushstring(L, allocated); xfree(allocated); @@ -1068,50 +992,35 @@ static int node_sexpr(lua_State *L) static int node_missing(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_is_missing(node)); return 1; } static int node_extra(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_is_extra(node)); return 1; } static int node_has_changes(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_has_changes(node)); return 1; } static int node_has_error(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_has_error(node)); return 1; } static int node_child(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t num = (uint32_t)lua_tointeger(L, 2); TSNode child = ts_node_child(node, num); @@ -1121,10 +1030,7 @@ static int node_child(lua_State *L) static int node_named_child(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t num = (uint32_t)lua_tointeger(L, 2); TSNode child = ts_node_named_child(node, num); @@ -1134,10 +1040,7 @@ static int node_named_child(lua_State *L) static int node_descendant_for_range(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint start = { (uint32_t)lua_tointeger(L, 2), (uint32_t)lua_tointeger(L, 3) }; TSPoint end = { (uint32_t)lua_tointeger(L, 4), @@ -1150,10 +1053,7 @@ static int node_descendant_for_range(lua_State *L) static int node_named_descendant_for_range(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint start = { (uint32_t)lua_tointeger(L, 2), (uint32_t)lua_tointeger(L, 3) }; TSPoint end = { (uint32_t)lua_tointeger(L, 4), @@ -1164,56 +1064,54 @@ static int node_named_descendant_for_range(lua_State *L) return 1; } -static int node_next_child(lua_State *L) +static TSTreeCursor *treecursor_check(lua_State *L, int index) { TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); if (!ud) { - return 0; + luaL_error(L, "TSTreeCursor expected"); } + return ud; +} - TSNode source; - if (!node_check(L, lua_upvalueindex(2), &source)) { - return 0; - } +static int node_next_child(lua_State *L) +{ + TSTreeCursor *cursor = treecursor_check(L, lua_upvalueindex(1)); + TSNode source = node_check(L, lua_upvalueindex(2)); // First call should return first child - if (ts_node_eq(source, ts_tree_cursor_current_node(ud))) { - if (ts_tree_cursor_goto_first_child(ud)) { + if (ts_node_eq(source, ts_tree_cursor_current_node(cursor))) { + if (ts_tree_cursor_goto_first_child(cursor)) { goto push; } else { - goto end; + return 0; } } - if (ts_tree_cursor_goto_next_sibling(ud)) { + if (ts_tree_cursor_goto_next_sibling(cursor)) { push: push_node(L, - ts_tree_cursor_current_node(ud), + ts_tree_cursor_current_node(cursor), lua_upvalueindex(2)); // [node] - const char *field = ts_tree_cursor_current_field_name(ud); + const char *field = ts_tree_cursor_current_field_name(cursor); if (field != NULL) { - lua_pushstring(L, ts_tree_cursor_current_field_name(ud)); + lua_pushstring(L, ts_tree_cursor_current_field_name(cursor)); } else { lua_pushnil(L); } // [node, field_name_or_nil] return 2; } -end: return 0; } static int node_iter_children(lua_State *L) { - TSNode source; - if (!node_check(L, 1, &source)) { - return 0; - } + TSNode node = node_check(L, 1); TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata] - *ud = ts_tree_cursor_new(source); + *ud = ts_tree_cursor_new(node); lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREECURSOR); // [udata, mt] lua_setmetatable(L, -2); // [udata] @@ -1225,17 +1123,14 @@ static int node_iter_children(lua_State *L) static int treecursor_gc(lua_State *L) { - TSTreeCursor *ud = luaL_checkudata(L, 1, TS_META_TREECURSOR); - ts_tree_cursor_delete(ud); + TSTreeCursor *cursor = treecursor_check(L, 1); + ts_tree_cursor_delete(cursor); return 0; } static int node_parent(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode parent = ts_node_parent(node); push_node(L, parent, 1); return 1; @@ -1243,10 +1138,7 @@ static int node_parent(lua_State *L) static int node_next_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_next_sibling(node); push_node(L, sibling, 1); return 1; @@ -1254,10 +1146,7 @@ static int node_next_sibling(lua_State *L) static int node_prev_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_prev_sibling(node); push_node(L, sibling, 1); return 1; @@ -1265,10 +1154,7 @@ static int node_prev_sibling(lua_State *L) static int node_next_named_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_next_named_sibling(node); push_node(L, sibling, 1); return 1; @@ -1276,10 +1162,7 @@ static int node_next_named_sibling(lua_State *L) static int node_prev_named_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_prev_named_sibling(node); push_node(L, sibling, 1); return 1; @@ -1287,10 +1170,7 @@ static int node_prev_named_sibling(lua_State *L) static int node_named_children(lua_State *L) { - TSNode source; - if (!node_check(L, 1, &source)) { - return 0; - } + TSNode source = node_check(L, 1); TSTreeCursor cursor = ts_tree_cursor_new(source); lua_newtable(L); @@ -1312,11 +1192,7 @@ static int node_named_children(lua_State *L) static int node_root(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + TSNode node = node_check(L, 1); TSNode root = ts_tree_root_node(node.tree); push_node(L, root, 1); return 1; @@ -1324,59 +1200,34 @@ static int node_root(lua_State *L) static int node_tree(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + node_check(L, 1); lua_getfenv(L, 1); // [udata, reftable] lua_rawgeti(L, -1, 1); // [udata, reftable, tree_udata] - return 1; } static int node_byte_length(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + TSNode node = node_check(L, 1); uint32_t start_byte = ts_node_start_byte(node); uint32_t end_byte = ts_node_end_byte(node); - lua_pushinteger(L, end_byte - start_byte); return 1; } static int node_equal(lua_State *L) { - TSNode node1; - if (!node_check(L, 1, &node1)) { - return 0; - } - - TSNode node2; - if (!node_check(L, 2, &node2)) { - return luaL_error(L, "TSNode expected"); - } - + TSNode node1 = node_check(L, 1); + TSNode node2 = node_check(L, 2); lua_pushboolean(L, ts_node_eq(node1, node2)); return 1; } int tslua_push_querycursor(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return luaL_error(L, "TSNode expected"); - } + TSNode node = node_check(L, 1); TSQuery *query = query_check(L, 2); - if (!query) { - return luaL_error(L, "TSQuery expected"); - } - TSQueryCursor *cursor = ts_query_cursor_new(); ts_query_cursor_exec(cursor, query, node); @@ -1388,7 +1239,7 @@ int tslua_push_querycursor(lua_State *L) if (lua_gettop(L) >= 5 && !lua_isnil(L, 5)) { if (!lua_istable(L, 5)) { - return luaL_error(L, "table expected"); + return luaL_argerror(L, 5, "table expected"); } lua_pushnil(L); // [dict, ..., nil] while (lua_next(L, 5)) { @@ -1443,7 +1294,6 @@ static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) static int querycursor_next_capture(lua_State *L) { TSQueryCursor *cursor = querycursor_check(L, 1); - TSQueryMatch match; uint32_t capture_index; if (!ts_query_cursor_next_capture(cursor, &match, &capture_index)) { @@ -1477,6 +1327,9 @@ static int querycursor_next_match(lua_State *L) static TSQueryCursor *querycursor_check(lua_State *L, int index) { TSQueryCursor **ud = luaL_checkudata(L, index, TS_META_QUERYCURSOR); + if (!ud || !(*ud)) { + luaL_argerror(L, index, "TSQueryCursor expected"); + } return *ud; } @@ -1487,17 +1340,26 @@ static int querycursor_gc(lua_State *L) return 0; } -static int querymatch_info(lua_State *L) +static TSQueryMatch *querymatch_check(lua_State *L, int index) { TSQueryMatch *ud = luaL_checkudata(L, 1, TS_META_QUERYMATCH); - lua_pushinteger(L, ud->id); - lua_pushinteger(L, ud->pattern_index + 1); + if (!ud) { + luaL_argerror(L, index, "TSQueryMatch expected"); + } + return ud; +} + +static int querymatch_info(lua_State *L) +{ + TSQueryMatch *match = querymatch_check(L, 1); + lua_pushinteger(L, match->id); + lua_pushinteger(L, match->pattern_index + 1); return 2; } static int querymatch_captures(lua_State *L) { - TSQueryMatch *match = luaL_checkudata(L, 1, TS_META_QUERYMATCH); + TSQueryMatch *match = querymatch_check(L, 1); lua_newtable(L); // [match, nodes, captures] for (size_t i = 0; i < match->capture_count; i++) { TSQueryCapture capture = match->captures[i]; @@ -1523,11 +1385,7 @@ int tslua_parse_query(lua_State *L) return luaL_error(L, "string expected"); } - const char *lang_name = lua_tostring(L, 1); - TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); - if (!lang) { - return luaL_error(L, "no such language: %s", lang_name); - } + TSLanguage *lang = lang_check(L, 1); size_t len; const char *src = lua_tolstring(L, 2, &len); @@ -1625,16 +1483,15 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err static TSQuery *query_check(lua_State *L, int index) { TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY); - return ud ? *ud : NULL; + if (!ud || !(*ud)) { + luaL_argerror(L, index, "TSQuery expected"); + } + return *ud; } static int query_gc(lua_State *L) { TSQuery *query = query_check(L, 1); - if (!query) { - return 0; - } - ts_query_delete(query); return 0; } @@ -1648,9 +1505,6 @@ static int query_tostring(lua_State *L) static int query_inspect(lua_State *L) { TSQuery *query = query_check(L, 1); - if (!query) { - return 0; - } // TSQueryInfo lua_createtable(L, 0, 2); // [retval] -- cgit From 597d4c63bda23b3c6450846848f1669daee17e3a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 19 Mar 2024 14:54:55 +0000 Subject: refactor(treesitter): reorder functions --- src/nvim/lua/treesitter.c | 409 +++++++++++++++++++++++----------------------- 1 file changed, 207 insertions(+), 202 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 0cf1ad2833..909ab214f5 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -51,129 +51,9 @@ typedef struct { # include "lua/treesitter.c.generated.h" #endif -// TSParser -static struct luaL_Reg parser_meta[] = { - { "__gc", parser_gc }, - { "__tostring", parser_tostring }, - { "parse", parser_parse }, - { "reset", parser_reset }, - { "set_included_ranges", parser_set_ranges }, - { "included_ranges", parser_get_ranges }, - { "set_timeout", parser_set_timeout }, - { "timeout", parser_get_timeout }, - { "_set_logger", parser_set_logger }, - { "_logger", parser_get_logger }, - { NULL, NULL } -}; - -// TSTree -static struct luaL_Reg tree_meta[] = { - { "__gc", tree_gc }, - { "__tostring", tree_tostring }, - { "root", tree_root }, - { "edit", tree_edit }, - { "included_ranges", tree_get_ranges }, - { "copy", tree_copy }, - { NULL, NULL } -}; - -// TSNode -static struct luaL_Reg node_meta[] = { - { "__tostring", node_tostring }, - { "__eq", node_eq }, - { "__len", node_child_count }, - { "id", node_id }, - { "range", node_range }, - { "start", node_start }, - { "end_", node_end }, - { "type", node_type }, - { "symbol", node_symbol }, - { "field", node_field }, - { "named", node_named }, - { "missing", node_missing }, - { "extra", node_extra }, - { "has_changes", node_has_changes }, - { "has_error", node_has_error }, - { "sexpr", node_sexpr }, - { "child_count", node_child_count }, - { "named_child_count", node_named_child_count }, - { "child", node_child }, - { "named_child", node_named_child }, - { "descendant_for_range", node_descendant_for_range }, - { "named_descendant_for_range", node_named_descendant_for_range }, - { "parent", node_parent }, - { "iter_children", node_iter_children }, - { "next_sibling", node_next_sibling }, - { "prev_sibling", node_prev_sibling }, - { "next_named_sibling", node_next_named_sibling }, - { "prev_named_sibling", node_prev_named_sibling }, - { "named_children", node_named_children }, - { "root", node_root }, - { "tree", node_tree }, - { "byte_length", node_byte_length }, - { "equal", node_equal }, - - { NULL, NULL } -}; - -// TSQuery -static struct luaL_Reg query_meta[] = { - { "__gc", query_gc }, - { "__tostring", query_tostring }, - { "inspect", query_inspect }, - { NULL, NULL } -}; - -// TSQueryCursor -static struct luaL_Reg querycursor_meta[] = { - { "remove_match", querycursor_remove_match }, - { "next_capture", querycursor_next_capture }, - { "next_match", querycursor_next_match }, - { "__gc", querycursor_gc }, - { NULL, NULL } -}; - -// TSQueryMatch -static struct luaL_Reg querymatch_meta[] = { - { "info", querymatch_info }, - { "captures", querymatch_captures }, - { NULL, NULL } -}; - -static struct luaL_Reg treecursor_meta[] = { - { "__gc", treecursor_gc }, - { NULL, NULL } -}; - static PMap(cstr_t) langs = MAP_INIT; -static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) -{ - if (luaL_newmetatable(L, tname)) { // [meta] - luaL_register(L, NULL, meta); - - lua_pushvalue(L, -1); // [meta, meta] - lua_setfield(L, -2, "__index"); // [meta] - } - lua_pop(L, 1); // [] (don't use it now) -} - -/// Init the tslua library. -/// -/// All global state is stored in the registry of the lua_State. -void tslua_init(lua_State *L) -{ - // type metatables - build_meta(L, TS_META_PARSER, parser_meta); - build_meta(L, TS_META_TREE, tree_meta); - build_meta(L, TS_META_NODE, node_meta); - build_meta(L, TS_META_QUERY, query_meta); - build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); - build_meta(L, TS_META_QUERYMATCH, querymatch_meta); - build_meta(L, TS_META_TREECURSOR, treecursor_meta); - - ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); -} +// TSLanguage int tslua_has_language(lua_State *L) { @@ -311,6 +191,22 @@ int tslua_inspect_lang(lua_State *L) return 1; } +// TSParser + +static struct luaL_Reg parser_meta[] = { + { "__gc", parser_gc }, + { "__tostring", parser_tostring }, + { "parse", parser_parse }, + { "reset", parser_reset }, + { "set_included_ranges", parser_set_ranges }, + { "included_ranges", parser_get_ranges }, + { "set_timeout", parser_set_timeout }, + { "timeout", parser_get_timeout }, + { "_set_logger", parser_set_logger }, + { "_logger", parser_get_logger }, + { NULL, NULL } +}; + int tslua_push_parser(lua_State *L) { TSLanguage *lang = lang_check(L, 1); @@ -497,54 +393,6 @@ static int parser_reset(lua_State *L) return 0; } -static int tree_copy(lua_State *L) -{ - TSLuaTree *ud = tree_check(L, 1); - TSTree *copy = ts_tree_copy(ud->tree); - push_tree(L, copy); // [tree] - - return 1; -} - -static int tree_edit(lua_State *L) -{ - if (lua_gettop(L) < 10) { - lua_pushstring(L, "not enough args to tree:edit()"); - return lua_error(L); - } - - TSLuaTree *ud = tree_check(L, 1); - - uint32_t start_byte = (uint32_t)luaL_checkint(L, 2); - uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3); - uint32_t new_end_byte = (uint32_t)luaL_checkint(L, 4); - TSPoint start_point = { (uint32_t)luaL_checkint(L, 5), (uint32_t)luaL_checkint(L, 6) }; - TSPoint old_end_point = { (uint32_t)luaL_checkint(L, 7), (uint32_t)luaL_checkint(L, 8) }; - TSPoint new_end_point = { (uint32_t)luaL_checkint(L, 9), (uint32_t)luaL_checkint(L, 10) }; - - TSInputEdit edit = { start_byte, old_end_byte, new_end_byte, - start_point, old_end_point, new_end_point }; - - ts_tree_edit(ud->tree, &edit); - - return 0; -} - -static int tree_get_ranges(lua_State *L) -{ - TSLuaTree *ud = tree_check(L, 1); - - bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); - - uint32_t len; - TSRange *ranges = ts_tree_included_ranges(ud->tree, &len); - - push_ranges(L, ranges, len, include_bytes); - - xfree(ranges); - return 1; -} - static void range_err(lua_State *L) { luaL_error(L, "Ranges can only be made from 6 element long tables or nodes."); @@ -598,7 +446,7 @@ static void range_from_lua(lua_State *L, TSRange *range) .start_byte = start_byte, .end_byte = end_byte, }; - } else if (node_check2(L, -1, &node)) { + } else if (node_check_opt(L, -1, &node)) { *range = (TSRange) { .start_point = ts_node_start_point(node), .end_point = ts_node_end_point(node), @@ -740,7 +588,17 @@ static int parser_get_logger(lua_State *L) return 1; } -// Tree methods +// TSTree + +static struct luaL_Reg tree_meta[] = { + { "__gc", tree_gc }, + { "__tostring", tree_tostring }, + { "root", tree_root }, + { "edit", tree_edit }, + { "included_ranges", tree_get_ranges }, + { "copy", tree_copy }, + { NULL, NULL } +}; /// Push tree interface on to the lua stack. /// @@ -779,6 +637,54 @@ static TSLuaTree *tree_check(lua_State *L, int index) return ud; } +static int tree_copy(lua_State *L) +{ + TSLuaTree *ud = tree_check(L, 1); + TSTree *copy = ts_tree_copy(ud->tree); + push_tree(L, copy); // [tree] + + return 1; +} + +static int tree_edit(lua_State *L) +{ + if (lua_gettop(L) < 10) { + lua_pushstring(L, "not enough args to tree:edit()"); + return lua_error(L); + } + + TSLuaTree *ud = tree_check(L, 1); + + uint32_t start_byte = (uint32_t)luaL_checkint(L, 2); + uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3); + uint32_t new_end_byte = (uint32_t)luaL_checkint(L, 4); + TSPoint start_point = { (uint32_t)luaL_checkint(L, 5), (uint32_t)luaL_checkint(L, 6) }; + TSPoint old_end_point = { (uint32_t)luaL_checkint(L, 7), (uint32_t)luaL_checkint(L, 8) }; + TSPoint new_end_point = { (uint32_t)luaL_checkint(L, 9), (uint32_t)luaL_checkint(L, 10) }; + + TSInputEdit edit = { start_byte, old_end_byte, new_end_byte, + start_point, old_end_point, new_end_point }; + + ts_tree_edit(ud->tree, &edit); + + return 0; +} + +static int tree_get_ranges(lua_State *L) +{ + TSLuaTree *ud = tree_check(L, 1); + + bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); + + uint32_t len; + TSRange *ranges = ts_tree_included_ranges(ud->tree, &len); + + push_ranges(L, ranges, len, include_bytes); + + xfree(ranges); + return 1; +} + static int tree_gc(lua_State *L) { TSLuaTree *ud = tree_check(L, 1); @@ -800,7 +706,67 @@ static int tree_root(lua_State *L) return 1; } -// Node methods +// TSTreeCursor + +static struct luaL_Reg treecursor_meta[] = { + { "__gc", treecursor_gc }, + { NULL, NULL } +}; + +static TSTreeCursor *treecursor_check(lua_State *L, int index) +{ + TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); + if (!ud) { + luaL_error(L, "TSTreeCursor expected"); + } + return ud; +} + +static int treecursor_gc(lua_State *L) +{ + TSTreeCursor *cursor = treecursor_check(L, 1); + ts_tree_cursor_delete(cursor); + return 0; +} + +// TSNode +static struct luaL_Reg node_meta[] = { + { "__tostring", node_tostring }, + { "__eq", node_eq }, + { "__len", node_child_count }, + { "id", node_id }, + { "range", node_range }, + { "start", node_start }, + { "end_", node_end }, + { "type", node_type }, + { "symbol", node_symbol }, + { "field", node_field }, + { "named", node_named }, + { "missing", node_missing }, + { "extra", node_extra }, + { "has_changes", node_has_changes }, + { "has_error", node_has_error }, + { "sexpr", node_sexpr }, + { "child_count", node_child_count }, + { "named_child_count", node_named_child_count }, + { "child", node_child }, + { "named_child", node_named_child }, + { "descendant_for_range", node_descendant_for_range }, + { "named_descendant_for_range", node_named_descendant_for_range }, + { "parent", node_parent }, + { "iter_children", node_iter_children }, + { "next_sibling", node_next_sibling }, + { "prev_sibling", node_prev_sibling }, + { "next_named_sibling", node_next_named_sibling }, + { "prev_named_sibling", node_prev_named_sibling }, + { "named_children", node_named_children }, + { "root", node_root }, + { "tree", node_tree }, + { "byte_length", node_byte_length }, + { "equal", node_equal }, + + { NULL, NULL } +}; /// Push node interface on to the Lua stack /// @@ -824,7 +790,7 @@ static void push_node(lua_State *L, TSNode node, int uindex) lua_setfenv(L, -2); // [udata] } -static bool node_check2(lua_State *L, int index, TSNode *res) +static bool node_check_opt(lua_State *L, int index, TSNode *res) { TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); if (ud) { @@ -1064,15 +1030,6 @@ static int node_named_descendant_for_range(lua_State *L) return 1; } -static TSTreeCursor *treecursor_check(lua_State *L, int index) -{ - TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); - if (!ud) { - luaL_error(L, "TSTreeCursor expected"); - } - return ud; -} - static int node_next_child(lua_State *L) { TSTreeCursor *cursor = treecursor_check(L, lua_upvalueindex(1)); @@ -1121,13 +1078,6 @@ static int node_iter_children(lua_State *L) return 1; } -static int treecursor_gc(lua_State *L) -{ - TSTreeCursor *cursor = treecursor_check(L, 1); - ts_tree_cursor_delete(cursor); - return 0; -} - static int node_parent(lua_State *L) { TSNode node = node_check(L, 1); @@ -1223,6 +1173,16 @@ static int node_equal(lua_State *L) return 1; } +// TSQueryCursor + +static struct luaL_Reg querycursor_meta[] = { + { "remove_match", querycursor_remove_match }, + { "next_capture", querycursor_next_capture }, + { "next_match", querycursor_next_match }, + { "__gc", querycursor_gc }, + { NULL, NULL } +}; + int tslua_push_querycursor(lua_State *L) { TSNode node = node_check(L, 1); @@ -1279,18 +1239,6 @@ static int querycursor_remove_match(lua_State *L) return 0; } -static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) -{ - TSQueryMatch *ud = lua_newuserdata(L, sizeof(TSQueryMatch)); // [udata] - *ud = *match; - lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYMATCH); // [udata, meta] - lua_setmetatable(L, -2); // [udata] - - // Copy the fenv which contains the nodes tree. - lua_getfenv(L, uindex); // [udata, reftable] - lua_setfenv(L, -2); // [udata] -} - static int querycursor_next_capture(lua_State *L) { TSQueryCursor *cursor = querycursor_check(L, 1); @@ -1340,6 +1288,26 @@ static int querycursor_gc(lua_State *L) return 0; } +// TSQueryMatch + +static struct luaL_Reg querymatch_meta[] = { + { "info", querymatch_info }, + { "captures", querymatch_captures }, + { NULL, NULL } +}; + +static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) +{ + TSQueryMatch *ud = lua_newuserdata(L, sizeof(TSQueryMatch)); // [udata] + *ud = *match; + lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYMATCH); // [udata, meta] + lua_setmetatable(L, -2); // [udata] + + // Copy the fenv which contains the nodes tree. + lua_getfenv(L, uindex); // [udata, reftable] + lua_setfenv(L, -2); // [udata] +} + static TSQueryMatch *querymatch_check(lua_State *L, int index) { TSQueryMatch *ud = luaL_checkudata(L, 1, TS_META_QUERYMATCH); @@ -1377,7 +1345,14 @@ static int querymatch_captures(lua_State *L) return 1; } -// Query methods +// TSQuery + +static struct luaL_Reg query_meta[] = { + { "__gc", query_gc }, + { "__tostring", query_tostring }, + { "inspect", query_inspect }, + { NULL, NULL } +}; int tslua_parse_query(lua_State *L) { @@ -1559,3 +1534,33 @@ static int query_inspect(lua_State *L) return 1; } + +// Library init + +static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) +{ + if (luaL_newmetatable(L, tname)) { // [meta] + luaL_register(L, NULL, meta); + + lua_pushvalue(L, -1); // [meta, meta] + lua_setfield(L, -2, "__index"); // [meta] + } + lua_pop(L, 1); // [] (don't use it now) +} + +/// Init the tslua library. +/// +/// All global state is stored in the registry of the lua_State. +void tslua_init(lua_State *L) +{ + // type metatables + build_meta(L, TS_META_PARSER, parser_meta); + build_meta(L, TS_META_TREE, tree_meta); + build_meta(L, TS_META_NODE, node_meta); + build_meta(L, TS_META_QUERY, query_meta); + build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); + build_meta(L, TS_META_QUERYMATCH, querymatch_meta); + build_meta(L, TS_META_TREECURSOR, treecursor_meta); + + ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); +} -- cgit From 0f85aeb478a68c18a8195e69724e1cb618fec058 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 20 Mar 2024 09:35:29 +0000 Subject: fix(treesitter): treecursor regression - Also address some coverity warnings Fixes #27942 --- src/nvim/lua/treesitter.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 909ab214f5..0576fa87c2 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -144,6 +144,7 @@ static TSLanguage *lang_check(lua_State *L, int index) TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { luaL_error(L, "no such language: %s", lang_name); + return NULL; // Coverity doesn't know luaL_error is noreturn } return lang; } @@ -230,6 +231,7 @@ static TSParser *parser_check(lua_State *L, uint16_t index) TSParser **ud = luaL_checkudata(L, index, TS_META_PARSER); if (!ud || !(*ud)) { luaL_argerror(L, index, "TSParser expected"); + return NULL; // Coverity doesn't know luaL_error is noreturn } return *ud; } @@ -633,6 +635,7 @@ static TSLuaTree *tree_check(lua_State *L, int index) TSLuaTree *ud = luaL_checkudata(L, index, TS_META_TREE); if (!ud) { luaL_argerror(L, index, "TSTree expected"); + return NULL; // Coverity doesn't know luaL_error is noreturn } return ud; } @@ -715,9 +718,10 @@ static struct luaL_Reg treecursor_meta[] = { static TSTreeCursor *treecursor_check(lua_State *L, int index) { - TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); + TSTreeCursor *ud = luaL_checkudata(L, index, TS_META_TREECURSOR); if (!ud) { luaL_error(L, "TSTreeCursor expected"); + return NULL; // Coverity doesn't know luaL_error is noreturn } return ud; } @@ -805,6 +809,7 @@ static TSNode node_check(lua_State *L, int index) TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); if (!ud) { luaL_argerror(L, index, "TSNode expected"); + abort(); // Coverity doesn't know luaL_error is noreturn } return *ud; } @@ -1044,23 +1049,21 @@ static int node_next_child(lua_State *L) } } - if (ts_tree_cursor_goto_next_sibling(cursor)) { -push: - push_node(L, - ts_tree_cursor_current_node(cursor), - lua_upvalueindex(2)); // [node] + if (!ts_tree_cursor_goto_next_sibling(cursor)) { + return 0; + } - const char *field = ts_tree_cursor_current_field_name(cursor); +push: + push_node(L, ts_tree_cursor_current_node(cursor), lua_upvalueindex(2)); // [node] - if (field != NULL) { - lua_pushstring(L, ts_tree_cursor_current_field_name(cursor)); - } else { - lua_pushnil(L); - } // [node, field_name_or_nil] - return 2; - } + const char *field = ts_tree_cursor_current_field_name(cursor); - return 0; + if (field != NULL) { + lua_pushstring(L, ts_tree_cursor_current_field_name(cursor)); + } else { + lua_pushnil(L); + } // [node, field_name_or_nil] + return 2; } static int node_iter_children(lua_State *L) @@ -1277,6 +1280,7 @@ static TSQueryCursor *querycursor_check(lua_State *L, int index) TSQueryCursor **ud = luaL_checkudata(L, index, TS_META_QUERYCURSOR); if (!ud || !(*ud)) { luaL_argerror(L, index, "TSQueryCursor expected"); + return NULL; // Coverity doesn't know luaL_error is noreturn } return *ud; } @@ -1310,9 +1314,10 @@ static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) static TSQueryMatch *querymatch_check(lua_State *L, int index) { - TSQueryMatch *ud = luaL_checkudata(L, 1, TS_META_QUERYMATCH); + TSQueryMatch *ud = luaL_checkudata(L, index, TS_META_QUERYMATCH); if (!ud) { luaL_argerror(L, index, "TSQueryMatch expected"); + return NULL; // Coverity doesn't know luaL_error is noreturn } return ud; } @@ -1460,6 +1465,7 @@ static TSQuery *query_check(lua_State *L, int index) TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY); if (!ud || !(*ud)) { luaL_argerror(L, index, "TSQuery expected"); + return NULL; // Coverity doesn't know luaL_error is noreturn } return *ud; } -- cgit From 47388614cbcf357b1e4ee490fa6968a89ee00479 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 20 Mar 2024 11:05:43 +0000 Subject: refactor(treesitter): handle coverity warnings better --- src/nvim/lua/treesitter.c | 92 ++++++++++------------------------------------- 1 file changed, 18 insertions(+), 74 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 0576fa87c2..f2ced71ddc 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -144,7 +144,6 @@ static TSLanguage *lang_check(lua_State *L, int index) TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { luaL_error(L, "no such language: %s", lang_name); - return NULL; // Coverity doesn't know luaL_error is noreturn } return lang; } @@ -229,10 +228,7 @@ int tslua_push_parser(lua_State *L) static TSParser *parser_check(lua_State *L, uint16_t index) { TSParser **ud = luaL_checkudata(L, index, TS_META_PARSER); - if (!ud || !(*ud)) { - luaL_argerror(L, index, "TSParser expected"); - return NULL; // Coverity doesn't know luaL_error is noreturn - } + luaL_argcheck(L, *ud, index, "TSParser expected"); return *ud; } @@ -327,7 +323,7 @@ static int parser_parse(lua_State *L) TSParser *p = parser_check(L, 1); TSTree *old_tree = NULL; if (!lua_isnil(L, 2)) { - TSLuaTree *ud = tree_check(L, 2); + TSLuaTree *ud = luaL_checkudata(L, 2, TS_META_TREE); old_tree = ud ? ud->tree : NULL; } @@ -468,9 +464,7 @@ static int parser_set_ranges(lua_State *L) TSParser *p = parser_check(L, 1); - if (!lua_istable(L, 2)) { - return luaL_argerror(L, 2, "table expected."); - } + luaL_argcheck(L, lua_istable(L, 2), 2, "table expected."); size_t tbl_len = lua_objlen(L, 2); TSRange *ranges = xmalloc(sizeof(TSRange) * tbl_len); @@ -544,17 +538,9 @@ static int parser_set_logger(lua_State *L) { TSParser *p = parser_check(L, 1); - if (!lua_isboolean(L, 2)) { - return luaL_argerror(L, 2, "boolean expected"); - } - - if (!lua_isboolean(L, 3)) { - return luaL_argerror(L, 3, "boolean expected"); - } - - if (!lua_isfunction(L, 4)) { - return luaL_argerror(L, 4, "function expected"); - } + luaL_argcheck(L, lua_isboolean(L, 2), 2, "boolean expected"); + luaL_argcheck(L, lua_isboolean(L, 3), 3, "boolean expected"); + luaL_argcheck(L, lua_isfunction(L, 4), 4, "function expected"); TSLuaLoggerOpts *opts = xmalloc(sizeof(TSLuaLoggerOpts)); lua_pushvalue(L, 4); @@ -630,19 +616,9 @@ static void push_tree(lua_State *L, TSTree *tree) lua_setfenv(L, -2); // [udata] } -static TSLuaTree *tree_check(lua_State *L, int index) -{ - TSLuaTree *ud = luaL_checkudata(L, index, TS_META_TREE); - if (!ud) { - luaL_argerror(L, index, "TSTree expected"); - return NULL; // Coverity doesn't know luaL_error is noreturn - } - return ud; -} - static int tree_copy(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); TSTree *copy = ts_tree_copy(ud->tree); push_tree(L, copy); // [tree] @@ -656,7 +632,7 @@ static int tree_edit(lua_State *L) return lua_error(L); } - TSLuaTree *ud = tree_check(L, 1); + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); uint32_t start_byte = (uint32_t)luaL_checkint(L, 2); uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3); @@ -675,7 +651,7 @@ static int tree_edit(lua_State *L) static int tree_get_ranges(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); @@ -690,7 +666,7 @@ static int tree_get_ranges(lua_State *L) static int tree_gc(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); ts_tree_delete(ud->tree); return 0; } @@ -703,7 +679,7 @@ static int tree_tostring(lua_State *L) static int tree_root(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); TSNode root = ts_tree_root_node(ud->tree); push_node(L, root, 1); return 1; @@ -716,19 +692,9 @@ static struct luaL_Reg treecursor_meta[] = { { NULL, NULL } }; -static TSTreeCursor *treecursor_check(lua_State *L, int index) -{ - TSTreeCursor *ud = luaL_checkudata(L, index, TS_META_TREECURSOR); - if (!ud) { - luaL_error(L, "TSTreeCursor expected"); - return NULL; // Coverity doesn't know luaL_error is noreturn - } - return ud; -} - static int treecursor_gc(lua_State *L) { - TSTreeCursor *cursor = treecursor_check(L, 1); + TSTreeCursor *cursor = luaL_checkudata(L, 1, TS_META_TREECURSOR); ts_tree_cursor_delete(cursor); return 0; } @@ -807,10 +773,6 @@ static bool node_check_opt(lua_State *L, int index, TSNode *res) static TSNode node_check(lua_State *L, int index) { TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); - if (!ud) { - luaL_argerror(L, index, "TSNode expected"); - abort(); // Coverity doesn't know luaL_error is noreturn - } return *ud; } @@ -1037,7 +999,7 @@ static int node_named_descendant_for_range(lua_State *L) static int node_next_child(lua_State *L) { - TSTreeCursor *cursor = treecursor_check(L, lua_upvalueindex(1)); + TSTreeCursor *cursor = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); TSNode source = node_check(L, lua_upvalueindex(2)); // First call should return first child @@ -1201,9 +1163,7 @@ int tslua_push_querycursor(lua_State *L) } if (lua_gettop(L) >= 5 && !lua_isnil(L, 5)) { - if (!lua_istable(L, 5)) { - return luaL_argerror(L, 5, "table expected"); - } + luaL_argcheck(L, lua_istable(L, 5), 5, "table expected"); lua_pushnil(L); // [dict, ..., nil] while (lua_next(L, 5)) { // [dict, ..., key, value] @@ -1278,10 +1238,7 @@ static int querycursor_next_match(lua_State *L) static TSQueryCursor *querycursor_check(lua_State *L, int index) { TSQueryCursor **ud = luaL_checkudata(L, index, TS_META_QUERYCURSOR); - if (!ud || !(*ud)) { - luaL_argerror(L, index, "TSQueryCursor expected"); - return NULL; // Coverity doesn't know luaL_error is noreturn - } + luaL_argcheck(L, *ud, index, "TSQueryCursor expected"); return *ud; } @@ -1312,19 +1269,9 @@ static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) lua_setfenv(L, -2); // [udata] } -static TSQueryMatch *querymatch_check(lua_State *L, int index) -{ - TSQueryMatch *ud = luaL_checkudata(L, index, TS_META_QUERYMATCH); - if (!ud) { - luaL_argerror(L, index, "TSQueryMatch expected"); - return NULL; // Coverity doesn't know luaL_error is noreturn - } - return ud; -} - static int querymatch_info(lua_State *L) { - TSQueryMatch *match = querymatch_check(L, 1); + TSQueryMatch *match = luaL_checkudata(L, 1, TS_META_QUERYMATCH); lua_pushinteger(L, match->id); lua_pushinteger(L, match->pattern_index + 1); return 2; @@ -1332,7 +1279,7 @@ static int querymatch_info(lua_State *L) static int querymatch_captures(lua_State *L) { - TSQueryMatch *match = querymatch_check(L, 1); + TSQueryMatch *match = luaL_checkudata(L, 1, TS_META_QUERYMATCH); lua_newtable(L); // [match, nodes, captures] for (size_t i = 0; i < match->capture_count; i++) { TSQueryCapture capture = match->captures[i]; @@ -1463,10 +1410,7 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err static TSQuery *query_check(lua_State *L, int index) { TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY); - if (!ud || !(*ud)) { - luaL_argerror(L, index, "TSQuery expected"); - return NULL; // Coverity doesn't know luaL_error is noreturn - } + luaL_argcheck(L, *ud, index, "TSQuery expected"); return *ud; } -- cgit From f29c41d665fde8e03848db12093219466deceda2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 29 Mar 2024 18:37:07 +0800 Subject: test: add a bit more testing for vim.on_key() (#28095) Also: - Don't use NUMBUFLEN as buffer length as its unrelated. - Restore accidentally removed comment from last commit. --- src/nvim/lua/executor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d5d35c5295..9e4b698b69 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2066,7 +2066,7 @@ char *nlua_register_table_as_callable(const typval_T *const arg) void nlua_execute_on_key(int c) { - char buf[NUMBUFLEN]; + char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); lua_State *const lstate = global_lstate; -- cgit From e1ff2c51cad755d0ddc04a23df23e317d77023ed Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 31 Mar 2024 11:20:05 +0800 Subject: feat(lua): pass keys before mapping to vim.on_key() callback (#28098) Keys before mapping (i.e. typed keys) are passed as the second argument. --- src/nvim/lua/executor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9e4b698b69..cfc68dc08f 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2064,7 +2064,7 @@ char *nlua_register_table_as_callable(const typval_T *const arg) return name; } -void nlua_execute_on_key(int c) +void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len) { char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); @@ -2085,9 +2085,12 @@ void nlua_execute_on_key(int c) // [ vim, vim._on_key, buf ] lua_pushlstring(lstate, buf, buf_len); + // [ vim, vim._on_key, buf, typed_buf ] + lua_pushlstring(lstate, typed_buf, typed_len); + int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C - if (nlua_pcall(lstate, 1, 0)) { + if (nlua_pcall(lstate, 2, 0)) { nlua_error(lstate, _("Error executing vim.on_key Lua callback: %.*s")); } -- cgit From 533e01a75b71e93686e7bc9c79fe0172ca876d91 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 15 Apr 2024 11:06:54 -0500 Subject: fix(base64): properly handle embedded NULLs when decoding (#28349) --- src/nvim/lua/base64.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/base64.c b/src/nvim/lua/base64.c index c1f43a37d7..8fe918493a 100644 --- a/src/nvim/lua/base64.c +++ b/src/nvim/lua/base64.c @@ -45,12 +45,13 @@ static int nlua_base64_decode(lua_State *L) size_t src_len = 0; const char *src = lua_tolstring(L, 1, &src_len); - const char *ret = base64_decode(src, src_len); + size_t out_len = 0; + const char *ret = base64_decode(src, src_len, &out_len); if (ret == NULL) { return luaL_error(L, "Invalid input"); } - lua_pushstring(L, ret); + lua_pushlstring(L, ret, out_len); xfree((void *)ret); return 1; -- cgit From f150b62423d57b6f9fbe57330589937dfbb34f4a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 17 Apr 2024 05:44:06 +0800 Subject: fix(lua): only free luarefs when returning from API (#28373) --- src/nvim/lua/converter.c | 52 +++++++++++++++++++++++++----------------------- src/nvim/lua/converter.h | 6 ++++++ src/nvim/lua/executor.c | 12 +++++------ src/nvim/lua/stdlib.c | 2 +- 4 files changed, 40 insertions(+), 32 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index bba771f8a5..38ccb03cfc 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -597,9 +597,9 @@ static bool typval_conv_special = false; /// @param[in] tv typval_T to convert. /// /// @return true in case of success, false otherwise. -bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) +bool nlua_push_typval(lua_State *lstate, typval_T *const tv, int flags) { - typval_conv_special = special; + typval_conv_special = (flags & kNluaPushSpecial); const int initial_size = lua_gettop(lstate); if (!lua_checkstack(lstate, initial_size + 2)) { @@ -662,7 +662,7 @@ static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, /// Convert given String to lua string /// /// Leaves converted string on top of the stack. -void nlua_push_String(lua_State *lstate, const String s, bool special) +void nlua_push_String(lua_State *lstate, const String s, int flags) FUNC_ATTR_NONNULL_ALL { lua_pushlstring(lstate, s.data, s.size); @@ -671,7 +671,7 @@ void nlua_push_String(lua_State *lstate, const String s, bool special) /// Convert given Integer to lua number /// /// Leaves converted number on top of the stack. -void nlua_push_Integer(lua_State *lstate, const Integer n, bool special) +void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) FUNC_ATTR_NONNULL_ALL { lua_pushnumber(lstate, (lua_Number)n); @@ -680,10 +680,10 @@ void nlua_push_Integer(lua_State *lstate, const Integer n, bool special) /// Convert given Float to lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Float(lua_State *lstate, const Float f, bool special) +void nlua_push_Float(lua_State *lstate, const Float f, int flags) FUNC_ATTR_NONNULL_ALL { - if (special) { + if (flags & kNluaPushSpecial) { nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat); nlua_push_val_idx(lstate); lua_pushnumber(lstate, (lua_Number)f); @@ -696,7 +696,7 @@ void nlua_push_Float(lua_State *lstate, const Float f, bool special) /// Convert given Float to lua boolean /// /// Leaves converted value on top of the stack. -void nlua_push_Boolean(lua_State *lstate, const Boolean b, bool special) +void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) FUNC_ATTR_NONNULL_ALL { lua_pushboolean(lstate, b); @@ -705,21 +705,21 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b, bool special) /// Convert given Dictionary to lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special) +void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, int flags) FUNC_ATTR_NONNULL_ALL { - if (dict.size == 0 && special) { + if (dict.size == 0 && (flags & kNluaPushSpecial)) { nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); } else { lua_createtable(lstate, 0, (int)dict.size); - if (dict.size == 0 && !special) { + if (dict.size == 0 && !(flags & kNluaPushSpecial)) { nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); lua_setmetatable(lstate, -2); } } for (size_t i = 0; i < dict.size; i++) { - nlua_push_String(lstate, dict.items[i].key, special); - nlua_push_Object(lstate, &dict.items[i].value, special); + nlua_push_String(lstate, dict.items[i].key, flags); + nlua_push_Object(lstate, &dict.items[i].value, flags); lua_rawset(lstate, -3); } } @@ -727,18 +727,18 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special /// Convert given Array to lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Array(lua_State *lstate, const Array array, bool special) +void nlua_push_Array(lua_State *lstate, const Array array, int flags) FUNC_ATTR_NONNULL_ALL { lua_createtable(lstate, (int)array.size, 0); for (size_t i = 0; i < array.size; i++) { - nlua_push_Object(lstate, &array.items[i], special); + nlua_push_Object(lstate, &array.items[i], flags); lua_rawseti(lstate, -2, (int)i + 1); } } #define GENERATE_INDEX_FUNCTION(type) \ - void nlua_push_##type(lua_State *lstate, const type item, bool special) \ + void nlua_push_##type(lua_State *lstate, const type item, int flags) \ FUNC_ATTR_NONNULL_ALL \ { \ lua_pushnumber(lstate, (lua_Number)(item)); \ @@ -753,12 +753,12 @@ GENERATE_INDEX_FUNCTION(Tabpage) /// Convert given Object to lua value /// /// Leaves converted value on top of the stack. -void nlua_push_Object(lua_State *lstate, Object *obj, bool special) +void nlua_push_Object(lua_State *lstate, Object *obj, int flags) FUNC_ATTR_NONNULL_ALL { switch (obj->type) { case kObjectTypeNil: - if (special) { + if (flags & kNluaPushSpecial) { lua_pushnil(lstate); } else { nlua_pushref(lstate, nlua_global_refs->nil_ref); @@ -766,13 +766,15 @@ void nlua_push_Object(lua_State *lstate, Object *obj, bool special) break; case kObjectTypeLuaRef: { nlua_pushref(lstate, obj->data.luaref); - api_free_luaref(obj->data.luaref); - obj->data.luaref = LUA_NOREF; + if (flags & kNluaPushFreeRefs) { + api_free_luaref(obj->data.luaref); + obj->data.luaref = LUA_NOREF; + } break; } #define ADD_TYPE(type, data_key) \ case kObjectType##type: { \ - nlua_push_##type(lstate, obj->data.data_key, special); \ + nlua_push_##type(lstate, obj->data.data_key, flags); \ break; \ } ADD_TYPE(Boolean, boolean) @@ -784,7 +786,7 @@ void nlua_push_Object(lua_State *lstate, Object *obj, bool special) #undef ADD_TYPE #define ADD_REMOTE_TYPE(type) \ case kObjectType##type: { \ - nlua_push_##type(lstate, (type)obj->data.integer, special); \ + nlua_push_##type(lstate, (type)obj->data.integer, flags); \ break; \ } ADD_REMOTE_TYPE(Buffer) @@ -1380,7 +1382,7 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) lua_pushstring(L, field->str); if (field->type == kObjectTypeNil) { - nlua_push_Object(L, (Object *)mem, false); + nlua_push_Object(L, (Object *)mem, 0); } else if (field->type == kObjectTypeInteger) { lua_pushinteger(L, *(Integer *)mem); } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow @@ -1391,11 +1393,11 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) } else if (field->type == kObjectTypeBoolean) { lua_pushboolean(L, *(Boolean *)mem); } else if (field->type == kObjectTypeString) { - nlua_push_String(L, *(String *)mem, false); + nlua_push_String(L, *(String *)mem, 0); } else if (field->type == kObjectTypeArray) { - nlua_push_Array(L, *(Array *)mem, false); + nlua_push_Array(L, *(Array *)mem, 0); } else if (field->type == kObjectTypeDictionary) { - nlua_push_Dictionary(L, *(Dictionary *)mem, false); + nlua_push_Dictionary(L, *(Dictionary *)mem, 0); } else if (field->type == kObjectTypeLuaRef) { nlua_pushref(L, *(LuaRef *)mem); } else { diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h index a502df80d9..d1ba61bcee 100644 --- a/src/nvim/lua/converter.h +++ b/src/nvim/lua/converter.h @@ -9,6 +9,12 @@ #define nlua_pop_Window nlua_pop_handle #define nlua_pop_Tabpage nlua_pop_handle +/// Flags for nlua_push_*() functions. +enum { + kNluaPushSpecial = 0x01, ///< Use lua-special-tbl when necessary + kNluaPushFreeRefs = 0x02, ///< Free luarefs to elide an api_luarefs_free_*() later +}; + #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 cfc68dc08f..9096cac619 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -103,7 +103,7 @@ typedef struct { if (args[i].v_type == VAR_UNKNOWN) { \ lua_pushnil(lstate); \ } else { \ - nlua_push_typval(lstate, &args[i], special); \ + nlua_push_typval(lstate, &args[i], (special) ? kNluaPushSpecial : 0); \ } \ } @@ -325,7 +325,7 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate) } ArrayOf(String) ret = runtime_get_named_thread(is_lua, pat, all); - nlua_push_Array(lstate, ret, true); + nlua_push_Array(lstate, ret, kNluaPushSpecial); api_free_array(ret); api_free_array(pat); @@ -1210,7 +1210,7 @@ int nlua_call(lua_State *lstate) }); if (!ERROR_SET(&err)) { - nlua_push_typval(lstate, &rettv, false); + nlua_push_typval(lstate, &rettv, 0); } tv_clear(&rettv); @@ -1261,7 +1261,7 @@ static int nlua_rpc(lua_State *lstate, bool request) ArenaMem res_mem = NULL; Object result = rpc_send_call(chan_id, name, args, &res_mem, &err); if (!ERROR_SET(&err)) { - nlua_push_Object(lstate, &result, false); + nlua_push_Object(lstate, &result, 0); arena_mem_free(res_mem); } } else { @@ -1564,7 +1564,7 @@ Object nlua_exec(const String str, const Array args, LuaRetMode mode, Arena *are } for (size_t i = 0; i < args.size; i++) { - nlua_push_Object(lstate, &args.items[i], false); + nlua_push_Object(lstate, &args.items[i], 0); } if (nlua_pcall(lstate, (int)args.size, 1)) { @@ -1611,7 +1611,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, nargs++; } for (size_t i = 0; i < args.size; i++) { - nlua_push_Object(lstate, &args.items[i], false); + nlua_push_Object(lstate, &args.items[i], 0); } if (nlua_pcall(lstate, nargs, 1)) { diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index a5262efcfa..788185f2b4 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -449,7 +449,7 @@ int nlua_getvar(lua_State *lstate) if (di == NULL) { return 0; // nil } - nlua_push_typval(lstate, &di->di_tv, false); + nlua_push_typval(lstate, &di->di_tv, 0); return 1; } -- cgit From 2b6c9bbe7f7ac950683e81129b76e35e35839ede Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 20 Apr 2024 02:33:44 +0900 Subject: perf(treesitter): incremental foldupdate Problem: While the fold level computation is incremental, the evaluation of the foldexpr is done on the full buffer. Despite that the foldexpr reads from the cache, it can take tens of milliseconds for moderately big (10K lines) buffers. Solution: Track the range of lines on which the foldexpr should be evaluated. --- src/nvim/lua/stdlib.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 788185f2b4..032cb246bf 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -543,14 +543,25 @@ static int nlua_iconv(lua_State *lstate) return 1; } -// Update foldlevels (e.g., by evaluating 'foldexpr') for all lines in the current window without -// invoking other side effects. Unlike `zx`, it does not close manually opened folds and does not -// open folds under the cursor. +// Update foldlevels (e.g., by evaluating 'foldexpr') for the given line range in the given window, +// without invoking other side effects. Unlike `zx`, it does not close manually opened folds and +// does not open folds under the cursor. static int nlua_foldupdate(lua_State *lstate) { - curwin->w_foldinvalid = true; // recompute folds - foldUpdate(curwin, 1, (linenr_T)MAXLNUM); - curwin->w_foldinvalid = false; + handle_T window = (handle_T)luaL_checkinteger(lstate, 1); + Error err = ERROR_INIT; + win_T *win = find_window_by_handle(window, &err); + if (ERROR_SET(&err)) { + nlua_push_errstr(lstate, err.msg); + api_clear_error(&err); + lua_error(lstate); + return 0; + } + + linenr_T start = (linenr_T)luaL_checkinteger(lstate, 2); + linenr_T end = (linenr_T)luaL_checkinteger(lstate, 3); + + foldUpdate(win, start + 1, end); return 0; } -- cgit From 032df963bb3fb0b5652e1817e9f4da986996fa6d Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 21 Apr 2024 13:39:08 +0100 Subject: refactor(treesitter): language loading --- src/nvim/lua/treesitter.c | 61 ++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 30 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index f2ced71ddc..f4bc454790 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -62,6 +62,35 @@ int tslua_has_language(lua_State *L) return 1; } +static TSLanguage *load_language(lua_State *L, const char *path, const char *lang_name, + const char *symbol) +{ + uv_lib_t lib; + if (uv_dlopen(path, &lib)) { + uv_dlclose(&lib); + luaL_error(L, "Failed to load parser for language '%s': uv_dlopen: %s", + lang_name, uv_dlerror(&lib)); + } + + char symbol_buf[128]; + snprintf(symbol_buf, sizeof(symbol_buf), "tree_sitter_%s", symbol); + + TSLanguage *(*lang_parser)(void); + if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) { + uv_dlclose(&lib); + luaL_error(L, "Failed to load parser: uv_dlsym: %s", uv_dlerror(&lib)); + } + + TSLanguage *lang = lang_parser(); + + if (lang == NULL) { + uv_dlclose(&lib); + luaL_error(L, "Failed to load parser %s: internal error", path); + } + + return lang; +} + // Creates the language into the internal language map. // // Returns true if the language is correctly loaded in the language map @@ -80,34 +109,7 @@ int tslua_add_language(lua_State *L) return 1; } -#define BUFSIZE 128 - char symbol_buf[BUFSIZE]; - snprintf(symbol_buf, BUFSIZE, "tree_sitter_%s", symbol_name); -#undef BUFSIZE - - uv_lib_t lib; - if (uv_dlopen(path, &lib)) { - snprintf(IObuff, IOSIZE, "Failed to load parser for language '%s': uv_dlopen: %s", - lang_name, uv_dlerror(&lib)); - uv_dlclose(&lib); - lua_pushstring(L, IObuff); - return lua_error(L); - } - - TSLanguage *(*lang_parser)(void); - if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) { - snprintf(IObuff, IOSIZE, "Failed to load parser: uv_dlsym: %s", - uv_dlerror(&lib)); - uv_dlclose(&lib); - lua_pushstring(L, IObuff); - return lua_error(L); - } - - TSLanguage *lang = lang_parser(); - if (lang == NULL) { - uv_dlclose(&lib); - return luaL_error(L, "Failed to load parser %s: internal error", path); - } + TSLanguage *lang = load_language(L, path, lang_name, symbol_name); uint32_t lang_version = ts_language_version(lang); if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION @@ -184,8 +186,7 @@ int tslua_inspect_lang(lua_State *L) lua_setfield(L, -2, "fields"); // [retval] - uint32_t lang_version = ts_language_version(lang); - lua_pushinteger(L, lang_version); // [retval, version] + lua_pushinteger(L, ts_language_version(lang)); // [retval, version] lua_setfield(L, -2, "_abi_version"); return 1; -- cgit From c32fcd1ed527236e52cfd78033685e713ec36d75 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 25 Apr 2024 08:26:49 +0800 Subject: refactor(source): remove unnecessary concatenation with Lua (#28499) --- src/nvim/lua/executor.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9096cac619..a76b8213e5 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1487,7 +1487,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name } } -int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) +void nlua_source_str(const char *code, char *name) { const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_STR; @@ -1495,22 +1495,11 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) current_sctx.sc_lnum = 0; estack_push(ETYPE_SCRIPT, name, 0); - garray_T ga; - char *line = NULL; - - ga_init(&ga, (int)sizeof(char *), 10); - while ((line = fgetline(0, cookie, 0, false)) != NULL) { - GA_APPEND(char *, &ga, line); - } - char *code = ga_concat_strings_sep(&ga, "\n"); size_t len = strlen(code); nlua_typval_exec(code, len, name, NULL, 0, false, NULL); estack_pop(); current_sctx = save_current_sctx; - ga_clear_strings(&ga); - xfree(code); - return OK; } /// Call a LuaCallable given some typvals -- cgit From 3711a0387a96d6531f3ae07a9b18fb8e2afc2e41 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 27 Apr 2024 09:21:46 +0200 Subject: refactor(build): make all generated c files headers There's no "rule" or bad practice or whatever that says we cannot generate c files. it is is just that we have ~20 generated headers and ~2 generated sources and there is nothing in these two generated source files which sets them aparts. Lua bindings are not different from rpc bindings, and pathdef is not different from versiondef. So to simplify build logic and ease the future port to build.zig, streamline the build to only have generated headers, no direct generated .c files. Also "nlua_add_api_functions" had its prototype duplicated twice which defeated the point of having mandatory prototypes (one source of truth). --- src/nvim/lua/api_wrappers.c | 18 ++++++++++++++++++ src/nvim/lua/executor.h | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/nvim/lua/api_wrappers.c (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c new file mode 100644 index 0000000000..2b7b0c6471 --- /dev/null +++ b/src/nvim/lua/api_wrappers.c @@ -0,0 +1,18 @@ +#include +#include +#include + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/dispatch.h" +#include "nvim/api/private/helpers.h" +#include "nvim/ex_docmd.h" +#include "nvim/ex_getln.h" +#include "nvim/func_attr.h" +#include "nvim/globals.h" +#include "nvim/lua/converter.h" +#include "nvim/lua/executor.h" +#include "nvim/memory.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "lua_api_c_bindings.generated.h" +#endif diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index ebcd62122f..299df2fdde 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -12,7 +12,7 @@ #include "nvim/types_defs.h" #include "nvim/usercmd.h" // IWYU pragma: keep -// Generated by msgpack-gen.lua +// Generated by generators/gen_api_dispatch.lua void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; typedef struct { -- cgit From 0df681a91d6b86395609e6fc40efb4d8623d72c9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 29 Apr 2024 14:12:39 +0200 Subject: fix(treesitter): make tests for memoize more robust Instead of painfully messing with timing to determine if queries were reparsed, we can simply keep a counter next to the call to ts_query_new Also memoization had a hidden dependency on the garbage collection of the the key, a hash value which never is kept around in memory. this was done intentionally as the hash does not capture all relevant state for the query (external included files) even if actual query objects still would be reachable in memory. To make the test fully deterministic in CI, we explicitly control GC. --- src/nvim/lua/treesitter.c | 1 + src/nvim/lua/treesitter.h | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index f4bc454790..8befc6d32d 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -1318,6 +1318,7 @@ int tslua_parse_query(lua_State *L) size_t len; const char *src = lua_tolstring(L, 2, &len); + tslua_query_parse_count++; uint32_t error_offset; TSQueryError error_type; TSQuery *query = ts_query_new(lang, src, (uint32_t)len, &error_offset, &error_type); diff --git a/src/nvim/lua/treesitter.h b/src/nvim/lua/treesitter.h index 4ef9a10602..14df06e184 100644 --- a/src/nvim/lua/treesitter.h +++ b/src/nvim/lua/treesitter.h @@ -1,7 +1,12 @@ #pragma once #include // IWYU pragma: keep +#include + +#include "nvim/macros_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/treesitter.h.generated.h" #endif + +EXTERN uint64_t tslua_query_parse_count INIT( = 0); -- cgit From 037ea6e786b5d05f4a8965e4c2ba6aa60ec7c01a Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Wed, 10 Apr 2024 11:42:46 +0200 Subject: feat(api): add nvim__redraw for more granular redrawing Experimental and subject to future changes. Add a way to redraw certain elements that are not redrawn while Nvim is waiting for input, or currently have no API to do so. This API covers all that can be done with the :redraw* commands, in addition to the following new features: - Immediately move the cursor to a (non-current) window. - Target a specific window or buffer to mark for redraw. - Mark a buffer range for redraw (replaces nvim__buf_redraw_range()). - Redraw the 'statuscolumn'. --- src/nvim/lua/executor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 299df2fdde..32fde3853b 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -43,7 +43,7 @@ typedef enum { kRetLuaref, ///< return value becomes a single Luaref, regardless of type (except NIL) } LuaRetMode; -/// To use with kRetNilBool for quick thuthyness check +/// To use with kRetNilBool for quick truthiness check #define LUARET_TRUTHY(res) ((res).type == kObjectTypeBoolean && (res).data.boolean == true) #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit From 4caf71af58f34726bf6f1d8a2d5ddeaf650e6286 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Mon, 22 Apr 2024 23:46:43 +0900 Subject: refactor(fold): avoid coverity false-positive Also add some more argument checks. --- src/nvim/lua/stdlib.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 032cb246bf..22ee0a1c98 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -549,19 +549,21 @@ static int nlua_iconv(lua_State *lstate) static int nlua_foldupdate(lua_State *lstate) { handle_T window = (handle_T)luaL_checkinteger(lstate, 1); - Error err = ERROR_INIT; - win_T *win = find_window_by_handle(window, &err); - if (ERROR_SET(&err)) { - nlua_push_errstr(lstate, err.msg); - api_clear_error(&err); - lua_error(lstate); - return 0; + win_T *win = handle_get_window(window); + if (!win) { + return luaL_error(lstate, "invalid window"); + } + // input is zero-based end-exclusive range + linenr_T top = (linenr_T)luaL_checkinteger(lstate, 2) + 1; + if (top < 1 || top > win->w_buffer->b_ml.ml_line_count) { + return luaL_error(lstate, "invalid top"); + } + linenr_T bot = (linenr_T)luaL_checkinteger(lstate, 3); + if (top > bot) { + return luaL_error(lstate, "invalid bot"); } - linenr_T start = (linenr_T)luaL_checkinteger(lstate, 2); - linenr_T end = (linenr_T)luaL_checkinteger(lstate, 3); - - foldUpdate(win, start + 1, end); + foldUpdate(win, top, bot); return 0; } -- cgit From 4b029163345333a2c6975cd0dace6613b036ae47 Mon Sep 17 00:00:00 2001 From: vanaigr Date: Thu, 16 May 2024 09:57:58 -0500 Subject: perf(treesitter): use child_containing_descendant() in has-ancestor? (#28512) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: `has-ancestor?` is O(n²) for the depth of the tree since it iterates over each of the node's ancestors (bottom-up), and each ancestor takes O(n) time. This happens because tree-sitter's nodes don't store their parent nodes, and the tree is searched (top-down) each time a new parent is requested. Solution: Make use of new `ts_node_child_containing_descendant()` in tree-sitter v0.22.6 (which is now the minimum required version) to rewrite the `has-ancestor?` predicate in C to become O(n). For a sample file, decreases the time taken by `has-ancestor?` from 360ms to 6ms. --- src/nvim/lua/treesitter.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'src/nvim/lua') diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 8befc6d32d..e87cf756a8 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -725,6 +725,8 @@ static struct luaL_Reg node_meta[] = { { "descendant_for_range", node_descendant_for_range }, { "named_descendant_for_range", node_named_descendant_for_range }, { "parent", node_parent }, + { "__has_ancestor", __has_ancestor }, + { "child_containing_descendant", node_child_containing_descendant }, { "iter_children", node_iter_children }, { "next_sibling", node_next_sibling }, { "prev_sibling", node_prev_sibling }, @@ -1052,6 +1054,49 @@ static int node_parent(lua_State *L) return 1; } +static int __has_ancestor(lua_State *L) +{ + TSNode descendant = node_check(L, 1); + if (lua_type(L, 2) != LUA_TTABLE) { + lua_pushboolean(L, false); + return 1; + } + int const pred_len = (int)lua_objlen(L, 2); + + TSNode node = ts_tree_root_node(descendant.tree); + while (!ts_node_is_null(node)) { + char const *node_type = ts_node_type(node); + size_t node_type_len = strlen(node_type); + + for (int i = 3; i <= pred_len; i++) { + lua_rawgeti(L, 2, i); + if (lua_type(L, -1) == LUA_TSTRING) { + size_t check_len; + char const *check_str = lua_tolstring(L, -1, &check_len); + if (node_type_len == check_len && memcmp(node_type, check_str, check_len) == 0) { + lua_pushboolean(L, true); + return 1; + } + } + lua_pop(L, 1); + } + + node = ts_node_child_containing_descendant(node, descendant); + } + + lua_pushboolean(L, false); + return 1; +} + +static int node_child_containing_descendant(lua_State *L) +{ + TSNode node = node_check(L, 1); + TSNode descendant = node_check(L, 2); + TSNode child = ts_node_child_containing_descendant(node, descendant); + push_node(L, child, 1); + return 1; +} + static int node_next_sibling(lua_State *L) { TSNode node = node_check(L, 1); -- cgit