aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/treesitter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/lua/treesitter.c')
-rw-r--r--src/nvim/lua/treesitter.c200
1 files changed, 120 insertions, 80 deletions
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index e3fa48f530..37929093e3 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -5,22 +5,20 @@
// NB: this file mostly contains a generic lua interface for tree-sitter
// trees and nodes, and could be broken out as a reusable lua package
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
#include <assert.h>
-
+#include <inttypes.h>
+#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
-#include <lauxlib.h>
-
-#include "tree_sitter/api.h"
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nvim/api/private/helpers.h"
+#include "nvim/buffer.h"
#include "nvim/lua/treesitter.h"
-#include "nvim/api/private/handle.h"
#include "nvim/memline.h"
-#include "nvim/buffer.h"
+#include "tree_sitter/api.h"
#define TS_META_PARSER "treesitter_parser"
#define TS_META_TREE "treesitter_tree"
@@ -80,6 +78,10 @@ static struct luaL_Reg node_meta[] = {
{ "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 },
+ { "prev_named_sibling", node_prev_named_sibling },
{ NULL, NULL }
};
@@ -101,7 +103,7 @@ static struct luaL_Reg treecursor_meta[] = {
{ NULL, NULL }
};
-static PMap(cstr_t) *langs;
+static PMap(cstr_t) langs = MAP_INIT;
static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
{
@@ -119,8 +121,6 @@ static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
/// all global state is stored in the regirstry of the lua_State
void tslua_init(lua_State *L)
{
- langs = pmap_new(cstr_t)();
-
// type metatables
build_meta(L, TS_META_PARSER, parser_meta);
build_meta(L, TS_META_TREE, tree_meta);
@@ -133,7 +133,7 @@ void tslua_init(lua_State *L)
int tslua_has_language(lua_State *L)
{
const char *lang_name = luaL_checkstring(L, 1);
- lua_pushboolean(L, pmap_has(cstr_t)(langs, lang_name));
+ lua_pushboolean(L, pmap_has(cstr_t)(&langs, lang_name));
return 1;
}
@@ -142,7 +142,7 @@ int tslua_add_language(lua_State *L)
const char *path = luaL_checkstring(L, 1);
const char *lang_name = luaL_checkstring(L, 2);
- if (pmap_has(cstr_t)(langs, lang_name)) {
+ if (pmap_has(cstr_t)(&langs, lang_name)) {
return 0;
}
@@ -177,15 +177,14 @@ int tslua_add_language(lua_State *L)
uint32_t lang_version = ts_language_version(lang);
if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION
|| lang_version > TREE_SITTER_LANGUAGE_VERSION) {
- return luaL_error(
- L,
- "ABI version mismatch for %s: supported between %d and %d, found %d",
- path,
- TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
- TREE_SITTER_LANGUAGE_VERSION, lang_version);
+ return luaL_error(L,
+ "ABI version mismatch for %s: supported between %d and %d, found %d",
+ path,
+ TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
+ TREE_SITTER_LANGUAGE_VERSION, lang_version);
}
- pmap_put(cstr_t)(langs, xstrdup(lang_name), lang);
+ pmap_put(cstr_t)(&langs, xstrdup(lang_name), lang);
lua_pushboolean(L, true);
return 1;
@@ -195,7 +194,7 @@ int tslua_inspect_lang(lua_State *L)
{
const char *lang_name = luaL_checkstring(L, 1);
- TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
+ TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
}
@@ -243,7 +242,7 @@ 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);
+ TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
}
@@ -261,7 +260,7 @@ 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);
}
@@ -283,8 +282,8 @@ static int parser_tostring(lua_State *L)
return 1;
}
-static const char *input_cb(void *payload, uint32_t byte_index,
- TSPoint position, uint32_t *bytes_read)
+static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position,
+ uint32_t *bytes_read)
{
buf_T *bp = payload;
#define BUFSIZE 256
@@ -316,9 +315,7 @@ static const char *input_cb(void *payload, uint32_t byte_index,
#undef BUFSIZE
}
-static void push_ranges(lua_State *L,
- const TSRange *ranges,
- const unsigned int length)
+static void push_ranges(lua_State *L, const TSRange *ranges, const unsigned int length)
{
lua_createtable(L, length, 0);
for (size_t i = 0; i < length; i++) {
@@ -359,40 +356,39 @@ static int parser_parse(lua_State *L)
// This switch is necessary because of the behavior of lua_isstring, that
// consider numbers as strings...
switch (lua_type(L, 3)) {
- case LUA_TSTRING:
- str = lua_tolstring(L, 3, &len);
- new_tree = ts_parser_parse_string(*p, old_tree, str, len);
- break;
+ case LUA_TSTRING:
+ str = lua_tolstring(L, 3, &len);
+ new_tree = ts_parser_parse_string(*p, old_tree, str, len);
+ break;
- case LUA_TNUMBER:
- bufnr = lua_tointeger(L, 3);
- buf = handle_get_buffer(bufnr);
+ case LUA_TNUMBER:
+ bufnr = lua_tointeger(L, 3);
+ buf = handle_get_buffer(bufnr);
- if (!buf) {
- return luaL_error(L, "invalid buffer handle: %d", bufnr);
- }
+ if (!buf) {
+ return luaL_error(L, "invalid buffer handle: %d", bufnr);
+ }
- input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
- new_tree = ts_parser_parse(*p, old_tree, input);
+ input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
+ new_tree = ts_parser_parse(*p, old_tree, input);
- break;
+ break;
- default:
- return luaL_error(L, "invalid argument to parser:parse()");
+ default:
+ return luaL_error(L, "invalid argument to parser:parse()");
}
// Sometimes parsing fails (timeout, or wrong parser ABI)
// In those case, just return an error.
if (!new_tree) {
- return luaL_error(L, "An error occured when parsing.");
+ return luaL_error(L, "An error occurred when parsing.");
}
// The new tree will be pushed to the stack, without copy, owwership is now to
// the lua GC.
// Old tree is still owned by the lua GC.
uint32_t n_ranges = 0;
- TSRange *changed = old_tree ? ts_tree_get_changed_ranges(
- old_tree, new_tree, &n_ranges) : NULL;
+ TSRange *changed = old_tree ? ts_tree_get_changed_ranges(old_tree, new_tree, &n_ranges) : NULL;
push_tree(L, new_tree, false); // [tree]
@@ -502,17 +498,15 @@ static void range_from_lua(lua_State *L, TSRange *range)
}
return;
error:
- luaL_error(
- L,
- "Ranges can only be made from 6 element long tables or nodes.");
+ 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);
@@ -521,9 +515,8 @@ static int parser_set_ranges(lua_State *L)
}
if (!lua_istable(L, 2)) {
- return luaL_error(
- L,
- "argument for parser:set_included_ranges() should be a table.");
+ return luaL_error(L,
+ "argument for parser:set_included_ranges() should be a table.");
}
size_t tbl_len = lua_objlen(L, 2);
@@ -888,9 +881,9 @@ static int node_descendant_for_range(lua_State *L)
return 0;
}
TSPoint start = { (uint32_t)lua_tointeger(L, 2),
- (uint32_t)lua_tointeger(L, 3) };
+ (uint32_t)lua_tointeger(L, 3) };
TSPoint end = { (uint32_t)lua_tointeger(L, 4),
- (uint32_t)lua_tointeger(L, 5) };
+ (uint32_t)lua_tointeger(L, 5) };
TSNode child = ts_node_descendant_for_point_range(node, start, end);
push_node(L, child, 1);
@@ -904,9 +897,9 @@ static int node_named_descendant_for_range(lua_State *L)
return 0;
}
TSPoint start = { (uint32_t)lua_tointeger(L, 2),
- (uint32_t)lua_tointeger(L, 3) };
+ (uint32_t)lua_tointeger(L, 3) };
TSPoint end = { (uint32_t)lua_tointeger(L, 4),
- (uint32_t)lua_tointeger(L, 5) };
+ (uint32_t)lua_tointeger(L, 5) };
TSNode child = ts_node_named_descendant_for_point_range(node, start, end);
push_node(L, child, 1);
@@ -915,8 +908,7 @@ static int node_named_descendant_for_range(lua_State *L)
static int node_next_child(lua_State *L)
{
- TSTreeCursor *ud = luaL_checkudata(
- L, lua_upvalueindex(1), TS_META_TREECURSOR);
+ TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR);
if (!ud) {
return 0;
}
@@ -937,19 +929,18 @@ static int node_next_child(lua_State *L)
if (ts_tree_cursor_goto_next_sibling(ud)) {
push:
- push_node(
- L,
- ts_tree_cursor_current_node(ud),
- lua_upvalueindex(2)); // [node]
+ push_node(L,
+ ts_tree_cursor_current_node(ud),
+ lua_upvalueindex(2)); // [node]
- const char * field = ts_tree_cursor_current_field_name(ud);
+ 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;
+ 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:
@@ -992,6 +983,50 @@ static int node_parent(lua_State *L)
return 1;
}
+static int node_next_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_next_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
+static int node_prev_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_prev_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
+static int node_next_named_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_next_named_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
+static int node_prev_named_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_prev_named_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
/// assumes the match table being on top of the stack
static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx)
{
@@ -1127,7 +1162,7 @@ int tslua_parse_query(lua_State *L)
}
const char *lang_name = lua_tostring(L, 1);
- TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
+ TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
}
@@ -1154,11 +1189,16 @@ int tslua_parse_query(lua_State *L)
static const char *query_err_string(TSQueryError err) {
switch (err) {
- case TSQueryErrorSyntax: return "invalid syntax";
- case TSQueryErrorNodeType: return "invalid node type";
- case TSQueryErrorField: return "invalid field";
- case TSQueryErrorCapture: return "invalid capture";
- default: return "error";
+ case TSQueryErrorSyntax:
+ return "invalid syntax";
+ case TSQueryErrorNodeType:
+ return "invalid node type";
+ case TSQueryErrorField:
+ return "invalid field";
+ case TSQueryErrorCapture:
+ return "invalid capture";
+ default:
+ return "error";
}
}