diff options
Diffstat (limited to 'src/nvim/lua')
-rw-r--r-- | src/nvim/lua/converter.c | 7 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 35 | ||||
-rw-r--r-- | src/nvim/lua/treesitter.c | 133 |
3 files changed, 149 insertions, 26 deletions
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 32e804d213..030df69caa 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -1249,6 +1249,13 @@ type_error: return ret; } +LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err) +{ + LuaRef rv = nlua_ref(lstate, -1); + lua_pop(lstate, 1); + return rv; +} + #define GENERATE_INDEX_FUNCTION(type) \ type nlua_pop_##type(lua_State *lstate, Error *err) \ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \ diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5ad9731a97..7722f9cdc3 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -845,7 +845,7 @@ void nlua_unref(lua_State *lstate, LuaRef ref) } } -void executor_free_luaref(LuaRef ref) +void api_free_luaref(LuaRef ref) { lua_State *const lstate = nlua_enter(); nlua_unref(lstate, ref); @@ -879,8 +879,8 @@ LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref) /// @param[out] ret_tv Location where result will be saved. /// /// @return Result of the execution. -void executor_eval_lua(const String str, typval_T *const arg, - typval_T *const ret_tv) +void nlua_typval_eval(const String str, typval_T *const arg, + typval_T *const ret_tv) FUNC_ATTR_NONNULL_ALL { #define EVALHEADER "local _A=select(1,...) return (" @@ -902,8 +902,8 @@ void executor_eval_lua(const String str, typval_T *const arg, } } -void executor_call_lua(const char *str, size_t len, typval_T *const args, - int argcount, typval_T *ret_tv) +void nlua_typval_call(const char *str, size_t len, typval_T *const args, + int argcount, typval_T *ret_tv) FUNC_ATTR_NONNULL_ALL { #define CALLHEADER "return " @@ -1006,14 +1006,14 @@ int typval_exec_lua_callable( /// Execute Lua string /// -/// Used for nvim_exec_lua(). +/// Used for nvim_exec_lua() and internally to execute a lua string. /// /// @param[in] str String to execute. /// @param[in] args array of ... args /// @param[out] err Location where error will be saved. /// /// @return Return value of the execution. -Object executor_exec_lua_api(const String str, const Array args, Error *err) +Object nlua_exec(const String str, const Array args, Error *err) { lua_State *const lstate = nlua_enter(); @@ -1040,17 +1040,30 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err) return nlua_pop_Object(lstate, false, err); } -Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args, - bool retval, Error *err) +/// call a LuaRef as a function (or table with __call metamethod) +/// +/// @param ref the reference to call (not consumed) +/// @param name if non-NULL, sent to callback as first arg +/// if NULL, only args are used +/// @param retval if true, convert return value to Object +/// if false, discard return value +/// @param err Error details, if any (if NULL, errors are echoed) +/// @return Return value of function, if retval was set. Otherwise NIL. +Object nlua_call_ref(LuaRef ref, const char *name, Array args, + bool retval, Error *err) { lua_State *const lstate = nlua_enter(); nlua_pushref(lstate, ref); - lua_pushstring(lstate, name); + int nargs = (int)args.size; + if (name != NULL) { + lua_pushstring(lstate, name); + nargs++; + } for (size_t i = 0; i < args.size; i++) { nlua_push_Object(lstate, args.items[i], false); } - if (lua_pcall(lstate, (int)args.size+1, retval ? 1 : 0, 0)) { + if (lua_pcall(lstate, nargs, retval ? 1 : 0, 0)) { // if err is passed, the caller will deal with the error. if (err) { size_t len; diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 138031237e..8be4b6f376 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -62,6 +62,7 @@ static struct luaL_Reg node_meta[] = { { "end_", node_end }, { "type", node_type }, { "symbol", node_symbol }, + { "field", node_field }, { "named", node_named }, { "missing", node_missing }, { "has_error", node_has_error }, @@ -73,6 +74,7 @@ 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 }, + { "iter_children", node_iter_children }, { "_rawquery", node_rawquery }, { NULL, NULL } }; @@ -84,12 +86,17 @@ static struct luaL_Reg query_meta[] = { { NULL, NULL } }; -// cursor is not exposed, but still needs garbage collection +// cursors are not exposed, but still needs garbage collection static struct luaL_Reg querycursor_meta[] = { { "__gc", querycursor_gc }, { NULL, NULL } }; +static struct luaL_Reg treecursor_meta[] = { + { "__gc", treecursor_gc }, + { NULL, NULL } +}; + static PMap(cstr_t) *langs; static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) @@ -116,6 +123,7 @@ void tslua_init(lua_State *L) build_meta(L, "treesitter_node", node_meta); build_meta(L, "treesitter_query", query_meta); build_meta(L, "treesitter_querycursor", querycursor_meta); + build_meta(L, "treesitter_treecursor", treecursor_meta); } int tslua_has_language(lua_State *L) @@ -278,22 +286,21 @@ static const char *input_cb(void *payload, uint32_t byte_index, } char_u *line = ml_get_buf(bp, position.row+1, false); size_t len = STRLEN(line); - if (position.column > len) { *bytes_read = 0; - } else { - size_t tocopy = MIN(len-position.column, BUFSIZE); - - memcpy(buf, line+position.column, tocopy); - // Translate embedded \n to NUL - memchrsub(buf, '\n', '\0', tocopy); - *bytes_read = (uint32_t)tocopy; - if (tocopy < BUFSIZE) { - // now add the final \n. If it didn't fit, input_cb will be called again - // on the same line with advanced column. - buf[tocopy] = '\n'; - (*bytes_read)++; - } + return ""; + } + size_t tocopy = MIN(len-position.column, BUFSIZE); + + memcpy(buf, line+position.column, tocopy); + // Translate embedded \n to NUL + memchrsub(buf, '\n', '\0', tocopy); + *bytes_read = (uint32_t)tocopy; + if (tocopy < BUFSIZE) { + // now add the final \n. If it didn't fit, input_cb will be called again + // on the same line with advanced column. + buf[tocopy] = '\n'; + (*bytes_read)++; } return buf; #undef BUFSIZE @@ -646,6 +653,34 @@ static int node_symbol(lua_State *L) return 1; } +static int node_field(lua_State *L) +{ + TSNode node; + if (!node_check(L, 1, &node)) { + return 0; + } + + size_t name_len; + const char *field_name = luaL_checklstring(L, 2, &name_len); + + TSTreeCursor cursor = ts_tree_cursor_new(node); + + lua_newtable(L); // [table] + unsigned int curr_index = 0; + + if (ts_tree_cursor_goto_first_child(&cursor)) { + do { + if (!STRCMP(field_name, ts_tree_cursor_current_field_name(&cursor))) { + push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node] + lua_rawseti(L, -2, ++curr_index); + } + } while (ts_tree_cursor_goto_next_sibling(&cursor)); + } + + ts_tree_cursor_delete(&cursor); + return 1; +} + static int node_named(lua_State *L) { TSNode node; @@ -746,6 +781,74 @@ static int node_named_descendant_for_range(lua_State *L) return 1; } +static int node_next_child(lua_State *L) +{ + TSTreeCursor *ud = luaL_checkudata( + L, lua_upvalueindex(1), "treesitter_treecursor"); + if (!ud) { + return 0; + } + + TSNode source; + if (!node_check(L, lua_upvalueindex(2), &source)) { + return 0; + } + + // 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)) { + goto push; + } else { + goto end; + } + } + + if (ts_tree_cursor_goto_next_sibling(ud)) { +push: + push_node( + L, + ts_tree_cursor_current_node(ud), + lua_upvalueindex(2)); // [node] + + const char * field = ts_tree_cursor_current_field_name(ud); + + if (field != NULL) { + lua_pushstring(L, ts_tree_cursor_current_field_name(ud)); + } 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; + } + + TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata] + *ud = ts_tree_cursor_new(source); + + lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_treecursor"); // [udata, mt] + lua_setmetatable(L, -2); // [udata] + lua_pushvalue(L, 1); // [udata, source_node] + lua_pushcclosure(L, node_next_child, 2); + + return 1; +} + +static int treecursor_gc(lua_State *L) +{ + TSTreeCursor *ud = luaL_checkudata(L, 1, "treesitter_treecursor"); + ts_tree_cursor_delete(ud); + return 0; +} + static int node_parent(lua_State *L) { TSNode node; |