mirror of
https://github.com/neovim/neovim.git
synced 2025-09-12 06:18:16 +00:00
tree-sitter: support pre-registration of languages
This commit is contained in:
@@ -38,7 +38,7 @@ local function create_parser(bufnr)
|
|||||||
end
|
end
|
||||||
local ft = a.nvim_buf_get_option(bufnr, "filetype")
|
local ft = a.nvim_buf_get_option(bufnr, "filetype")
|
||||||
local self = setmetatable({bufnr=bufnr, valid=false}, Parser)
|
local self = setmetatable({bufnr=bufnr, valid=false}, Parser)
|
||||||
self._parser = vim._create_ts_parser(ft.."_parser.so", ft)
|
self._parser = vim._create_ts_parser(ft)
|
||||||
self:parse_tree()
|
self:parse_tree()
|
||||||
local function cb(ev, ...)
|
local function cb(ev, ...)
|
||||||
-- TODO: use weakref to self, so that the parser is free'd is no plugin is
|
-- TODO: use weakref to self, so that the parser is free'd is no plugin is
|
||||||
|
@@ -824,34 +824,13 @@ void ex_luafile(exarg_T *const eap)
|
|||||||
|
|
||||||
static int create_tslua_parser(lua_State *L)
|
static int create_tslua_parser(lua_State *L)
|
||||||
{
|
{
|
||||||
if (lua_gettop(L) < 2) {
|
if (lua_gettop(L) < 1 || !lua_isstring(L, 1)) {
|
||||||
return 0;
|
return luaL_error(L, "string expected");
|
||||||
}
|
|
||||||
const char *path = lua_tostring(L,1);
|
|
||||||
const char *lang_name = lua_tostring(L,2);
|
|
||||||
|
|
||||||
// TODO: unsafe!
|
|
||||||
char symbol_buf[128] = "tree_sitter_";
|
|
||||||
STRCAT(symbol_buf, lang_name);
|
|
||||||
|
|
||||||
// TODO: we should maybe keep the uv_lib_t around, and close them
|
|
||||||
// at exit, to keep LeakSanitizer happy.
|
|
||||||
uv_lib_t lib;
|
|
||||||
if (uv_dlopen(path, &lib)) {
|
|
||||||
return luaL_error(L, "uv_dlopen: %s", uv_dlerror(&lib));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TSLanguage *(*lang_parser)(void);
|
const char *lang_name = lua_tostring(L,1);
|
||||||
if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) {
|
|
||||||
return luaL_error(L, "uv_dlsym: %s", uv_dlerror(&lib));
|
|
||||||
}
|
|
||||||
|
|
||||||
TSLanguage *lang = lang_parser();
|
return tslua_push_parser(L, lang_name);
|
||||||
if (lang == NULL) {
|
|
||||||
return luaL_error(L, "failed to load parser");
|
|
||||||
}
|
|
||||||
tslua_push_parser(L, lang);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
|
static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
|
||||||
@@ -860,4 +839,7 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
|
|||||||
|
|
||||||
lua_pushcfunction(lstate, create_tslua_parser);
|
lua_pushcfunction(lstate, create_tslua_parser);
|
||||||
lua_setfield(lstate, -2, "_create_ts_parser");
|
lua_setfield(lstate, -2, "_create_ts_parser");
|
||||||
|
|
||||||
|
lua_pushcfunction(lstate, ts_lua_register_lang);
|
||||||
|
lua_setfield(lstate, -2, "ts_add_language");
|
||||||
}
|
}
|
||||||
|
@@ -65,6 +65,8 @@ static struct luaL_Reg node_meta[] = {
|
|||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PMap(cstr_t) *langs;
|
||||||
|
|
||||||
void build_meta(lua_State *L, const luaL_Reg *meta)
|
void build_meta(lua_State *L, const luaL_Reg *meta)
|
||||||
{
|
{
|
||||||
// [env, target]
|
// [env, target]
|
||||||
@@ -86,6 +88,9 @@ void build_meta(lua_State *L, const luaL_Reg *meta)
|
|||||||
/// all global state is stored in the regirstry of the lua_State
|
/// all global state is stored in the regirstry of the lua_State
|
||||||
void tslua_init(lua_State *L)
|
void tslua_init(lua_State *L)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
langs = pmap_new(cstr_t)();
|
||||||
|
|
||||||
lua_createtable(L, 0, 0);
|
lua_createtable(L, 0, 0);
|
||||||
|
|
||||||
// type metatables
|
// type metatables
|
||||||
@@ -114,9 +119,55 @@ static int tslua_debug(lua_State *L)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tslua_push_parser(lua_State *L, TSLanguage *lang)
|
|
||||||
|
int ts_lua_register_lang(lua_State *L)
|
||||||
|
{
|
||||||
|
if (lua_gettop(L) < 2 || !lua_isstring(L, 1) || !lua_isstring(L, 2)) {
|
||||||
|
return luaL_error(L, "string expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *path = lua_tostring(L,1);
|
||||||
|
const char *lang_name = lua_tostring(L,2);
|
||||||
|
|
||||||
|
if (pmap_has(cstr_t)(langs, lang_name)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: unsafe!
|
||||||
|
char symbol_buf[128] = "tree_sitter_";
|
||||||
|
STRCAT(symbol_buf, lang_name);
|
||||||
|
|
||||||
|
// TODO: we should maybe keep the uv_lib_t around, and close them
|
||||||
|
// at exit, to keep LeakSanitizer happy.
|
||||||
|
uv_lib_t lib;
|
||||||
|
if (uv_dlopen(path, &lib)) {
|
||||||
|
return luaL_error(L, "Failed to load parser: uv_dlopen: %s", uv_dlerror(&lib));
|
||||||
|
}
|
||||||
|
|
||||||
|
TSLanguage *(*lang_parser)(void);
|
||||||
|
if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) {
|
||||||
|
return luaL_error(L, "Failed to load parser: uv_dlsym: %s", uv_dlerror(&lib));
|
||||||
|
}
|
||||||
|
|
||||||
|
TSLanguage *lang = lang_parser();
|
||||||
|
if (lang == NULL) {
|
||||||
|
return luaL_error(L, "Failed to load parser: internal error");
|
||||||
|
}
|
||||||
|
|
||||||
|
pmap_put(cstr_t)(langs, xstrdup(lang_name), lang);
|
||||||
|
|
||||||
|
lua_pushboolean(L, true);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tslua_push_parser(lua_State *L, const char *lang_name)
|
||||||
{
|
{
|
||||||
TSParser *parser = ts_parser_new();
|
TSParser *parser = ts_parser_new();
|
||||||
|
TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
|
||||||
|
if (!lang) {
|
||||||
|
return luaL_error(L, "no such language: %s", lang_name);
|
||||||
|
}
|
||||||
|
|
||||||
ts_parser_set_language(parser, lang);
|
ts_parser_set_language(parser, lang);
|
||||||
Tslua_parser *p = lua_newuserdata(L, sizeof(Tslua_parser)); // [udata]
|
Tslua_parser *p = lua_newuserdata(L, sizeof(Tslua_parser)); // [udata]
|
||||||
p->parser = parser;
|
p->parser = parser;
|
||||||
@@ -126,6 +177,7 @@ void tslua_push_parser(lua_State *L, TSLanguage *lang)
|
|||||||
lua_getfield(L, -1, "parser-meta"); // [udata, env, meta]
|
lua_getfield(L, -1, "parser-meta"); // [udata, env, meta]
|
||||||
lua_setmetatable(L, -3); // [udata, env]
|
lua_setmetatable(L, -3); // [udata, env]
|
||||||
lua_pop(L, 1); // [udata]
|
lua_pop(L, 1); // [udata]
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Tslua_parser *parser_check(lua_State *L)
|
static Tslua_parser *parser_check(lua_State *L)
|
||||||
|
Reference in New Issue
Block a user