feat(treesitter): replace nvim-treesitter with pack-managed parsers
This commit is contained in:
@@ -17,7 +17,7 @@ end, {
|
||||
complete = function(lead)
|
||||
return vim.tbl_filter(function(name)
|
||||
return name:find(lead, 1, true) == 1
|
||||
end, require("pack").names)
|
||||
end, require("pack").get_names())
|
||||
end,
|
||||
desc = "Reload a plugin config by name",
|
||||
})
|
||||
|
||||
+31
-10
@@ -24,6 +24,7 @@ end
|
||||
---@field name? string
|
||||
---@field version? string | vim.VersionRange
|
||||
---@field build? string[] | fun(self: ow.Pack.Plugin)
|
||||
---@field ts_parser? ow.TS.ParserField
|
||||
|
||||
---@class ow.Pack.Plugin : ow.Pack.PluginSpec
|
||||
---@field name string
|
||||
@@ -55,6 +56,7 @@ local function to_pack_spec(spec)
|
||||
version = spec.version,
|
||||
data = {
|
||||
build = spec.build,
|
||||
ts_parser = spec.ts_parser,
|
||||
},
|
||||
}
|
||||
end
|
||||
@@ -75,7 +77,15 @@ local function run_build(plugin)
|
||||
return
|
||||
end
|
||||
|
||||
log.error("invalid build parameter for %s", plugin.name)
|
||||
log.error("Invalid build parameter for %s", plugin.name)
|
||||
end
|
||||
|
||||
---@param plugin ow.Pack.Plugin
|
||||
local function run_ts_build(plugin)
|
||||
local ts = require("ts")
|
||||
for _, p in ipairs(ts.normalize(plugin.ts_parser)) do
|
||||
ts.build(plugin, p)
|
||||
end
|
||||
end
|
||||
|
||||
---@class ow.Pack.Event.Data
|
||||
@@ -90,7 +100,7 @@ end
|
||||
---@param plugin ow.Pack.Plugin
|
||||
---@param events ow.Pack.Event[]
|
||||
local function process_events(plugin, events)
|
||||
if not plugin.build then
|
||||
if not plugin.build and not plugin.ts_parser then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -99,7 +109,11 @@ local function process_events(plugin, events)
|
||||
and ev.event == "PackChanged"
|
||||
and (ev.data.kind == "install" or ev.data.kind == "update")
|
||||
then
|
||||
run_build(plugin)
|
||||
if plugin.ts_parser then
|
||||
run_ts_build(plugin)
|
||||
else
|
||||
run_build(plugin)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -111,15 +125,21 @@ local watcher = nil
|
||||
local timers = {}
|
||||
|
||||
---@class ow.Pack
|
||||
---@field names string[]
|
||||
---@field paths string[]
|
||||
---@field plugins ow.Pack.Plugin[]
|
||||
local M = {
|
||||
names = {},
|
||||
paths = {},
|
||||
plugins = {},
|
||||
}
|
||||
|
||||
---@return string[]
|
||||
function M.get_names()
|
||||
return vim.tbl_map(function(p) return p.name end, M.plugins)
|
||||
end
|
||||
|
||||
---@return string[]
|
||||
function M.get_paths()
|
||||
return vim.tbl_map(function(p) return p.path end, M.plugins)
|
||||
end
|
||||
|
||||
---@param name string
|
||||
function M.reload(name)
|
||||
local path = string.format("%s/lua/plugins/%s.lua", config_dir, name)
|
||||
@@ -247,12 +267,13 @@ function M.setup(specs)
|
||||
name = data.spec.name,
|
||||
version = data.spec.version,
|
||||
build = d.build,
|
||||
ts_parser = d.ts_parser,
|
||||
path = data.path,
|
||||
}
|
||||
table.insert(M.plugins, plugin)
|
||||
table.insert(M.names, plugin.name)
|
||||
table.insert(M.paths, plugin.path)
|
||||
vim.cmd.packadd(plugin.name)
|
||||
if not d.ts_parser then
|
||||
vim.cmd.packadd(plugin.name)
|
||||
end
|
||||
end
|
||||
})
|
||||
vim.api.nvim_del_autocmd(id)
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
local log = require("log")
|
||||
|
||||
local M = {}
|
||||
|
||||
---@class ow.TS.ParserSpec
|
||||
---@field lang string
|
||||
---@field location? string
|
||||
---@field generate? boolean
|
||||
---@field from_json? boolean
|
||||
|
||||
---@alias ow.TS.ParserField string | ow.TS.ParserSpec | ow.TS.ParserSpec[]
|
||||
|
||||
---@param plugin ow.Pack.Plugin
|
||||
---@param lang string
|
||||
---@return string
|
||||
local function parser_path(plugin, lang)
|
||||
return vim.fs.joinpath(plugin.path, "parser", lang .. ".so")
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
local function start_treesitter(buf)
|
||||
local ok, err = pcall(vim.treesitter.start, buf)
|
||||
if not ok then
|
||||
log.error(
|
||||
"Failed to enable treesitter for buffer %d: %s",
|
||||
buf,
|
||||
err
|
||||
)
|
||||
return
|
||||
end
|
||||
for _, win in ipairs(vim.fn.win_findbuf(buf)) do
|
||||
vim.wo[win].foldmethod = "expr"
|
||||
vim.wo[win].foldexpr = "v:lua.vim.treesitter.foldexpr()"
|
||||
end
|
||||
end
|
||||
|
||||
---@param lang string
|
||||
local function activate_open_buffers(lang)
|
||||
local fts = vim.treesitter.language.get_filetypes(lang)
|
||||
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
|
||||
if vim.api.nvim_buf_is_loaded(buf)
|
||||
and vim.list_contains(fts, vim.bo[buf].filetype)
|
||||
then
|
||||
start_treesitter(buf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param plugin ow.Pack.Plugin
|
||||
---@param spec ow.TS.ParserSpec
|
||||
function M.build(plugin, spec)
|
||||
local cwd = spec.location
|
||||
and vim.fs.joinpath(plugin.path, spec.location)
|
||||
or plugin.path
|
||||
local out = parser_path(plugin, spec.lang)
|
||||
vim.fn.mkdir(vim.fs.dirname(out), "p")
|
||||
|
||||
local function on_build(r)
|
||||
if r.code ~= 0 then
|
||||
log.error(
|
||||
"Failed to build parser for %s: %s",
|
||||
spec.lang,
|
||||
r.stderr or ""
|
||||
)
|
||||
return
|
||||
end
|
||||
vim.treesitter.language.add(spec.lang, { path = out })
|
||||
activate_open_buffers(spec.lang)
|
||||
end
|
||||
|
||||
local function do_build()
|
||||
vim.system(
|
||||
{ "tree-sitter", "build", "-o", out },
|
||||
{ cwd = cwd },
|
||||
vim.schedule_wrap(on_build)
|
||||
)
|
||||
end
|
||||
|
||||
if spec.generate then
|
||||
local cmd = {
|
||||
"tree-sitter", "generate",
|
||||
"--abi", tostring(vim.treesitter.language_version),
|
||||
}
|
||||
if spec.from_json ~= false then
|
||||
table.insert(cmd, "src/grammar.json")
|
||||
end
|
||||
vim.system(cmd, {
|
||||
cwd = cwd,
|
||||
env = { TREE_SITTER_JS_RUNTIME = "native" },
|
||||
}, vim.schedule_wrap(function(r)
|
||||
if r.code ~= 0 then
|
||||
log.error(
|
||||
"Failed to generate parser for %s: %s",
|
||||
spec.lang,
|
||||
r.stderr or ""
|
||||
)
|
||||
return
|
||||
end
|
||||
do_build()
|
||||
end))
|
||||
else
|
||||
do_build()
|
||||
end
|
||||
end
|
||||
|
||||
---@param field ow.TS.ParserField
|
||||
---@return ow.TS.ParserSpec[]
|
||||
function M.normalize(field)
|
||||
if type(field) == "string" then
|
||||
return { { lang = field } }
|
||||
end
|
||||
|
||||
if type(field) == "table" then
|
||||
if type(field.lang) == "string" then
|
||||
return { field }
|
||||
end
|
||||
if type(field[1]) == "table" then
|
||||
return field
|
||||
end
|
||||
end
|
||||
|
||||
error("invalid ts_parser value: " .. vim.inspect(field))
|
||||
end
|
||||
|
||||
---@param languages string[]
|
||||
local function collect_filetypes(languages)
|
||||
local filetypes = {}
|
||||
for _, lang in ipairs(languages) do
|
||||
for _, ft in ipairs(vim.treesitter.language.get_filetypes(lang)) do
|
||||
if not vim.list_contains(filetypes, ft) then
|
||||
table.insert(filetypes, ft)
|
||||
end
|
||||
end
|
||||
end
|
||||
return filetypes
|
||||
end
|
||||
|
||||
---@param opts { languages: string[] }
|
||||
function M.setup(opts)
|
||||
for _, plugin in ipairs(require("pack").plugins) do
|
||||
if plugin.ts_parser then
|
||||
for _, p in ipairs(M.normalize(plugin.ts_parser)) do
|
||||
local path = parser_path(plugin, p.lang)
|
||||
if vim.uv.fs_stat(path) then
|
||||
vim.treesitter.language.add(p.lang, { path = path })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = collect_filetypes(opts.languages),
|
||||
callback = function(ev)
|
||||
start_treesitter(ev.buf)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user