refactor(ts): own parser installation, split from pack
This commit is contained in:
@@ -22,7 +22,6 @@ for _, file in ipairs(files) do
|
||||
end
|
||||
end
|
||||
|
||||
local ts = require("ts")
|
||||
require("pack").setup({
|
||||
"https://github.com/navarasu/onedark.nvim",
|
||||
"https://github.com/ibhagwan/fzf-lua",
|
||||
@@ -42,105 +41,58 @@ require("pack").setup({
|
||||
"https://github.com/saghen/blink.cmp",
|
||||
version = vim.version.range("^1"),
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-bash",
|
||||
ts_parser = "bash",
|
||||
},
|
||||
-- required by cpp
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-c",
|
||||
ts_parser = "c",
|
||||
},
|
||||
{
|
||||
"https://github.com/stsewd/tree-sitter-comment",
|
||||
ts_parser = "comment",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-cpp",
|
||||
ts_parser = "cpp",
|
||||
},
|
||||
-- required by scss
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-css",
|
||||
ts_parser = "css",
|
||||
},
|
||||
{
|
||||
"https://github.com/gbprod/tree-sitter-gitcommit",
|
||||
ts_parser = "gitcommit",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-go",
|
||||
ts_parser = "go",
|
||||
},
|
||||
{
|
||||
"https://github.com/ngalaiko/tree-sitter-go-template",
|
||||
ts_parser = "gotmpl",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-html",
|
||||
ts_parser = "html",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-json",
|
||||
ts_parser = "json",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-luadoc",
|
||||
ts_parser = "luadoc",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-php",
|
||||
ts_parser = {
|
||||
{ lang = "php", location = "php" },
|
||||
{ lang = "php_only", location = "php_only" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-python",
|
||||
ts_parser = "python",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-rust",
|
||||
ts_parser = "rust",
|
||||
},
|
||||
{
|
||||
"https://github.com/serenadeai/tree-sitter-scss",
|
||||
ts_parser = "scss",
|
||||
},
|
||||
{
|
||||
"https://github.com/derekstride/tree-sitter-sql",
|
||||
version = "gh-pages",
|
||||
ts_parser = "sql",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-svelte",
|
||||
ts_parser = "svelte",
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-typescript",
|
||||
ts_parser = {
|
||||
{ lang = "typescript", location = "typescript" },
|
||||
{ lang = "tsx", location = "tsx" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-xml",
|
||||
ts_parser = {
|
||||
{ lang = "xml", location = "xml" },
|
||||
{ lang = "dtd", location = "dtd" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-yaml",
|
||||
ts_parser = "yaml",
|
||||
},
|
||||
{
|
||||
"https://github.com/georgeharker/tree-sitter-zsh",
|
||||
ts_parser = "zsh",
|
||||
},
|
||||
})
|
||||
|
||||
ts.setup({
|
||||
require("ts").setup({
|
||||
parsers = {
|
||||
"https://github.com/tree-sitter/tree-sitter-bash",
|
||||
-- required by cpp
|
||||
"https://github.com/tree-sitter/tree-sitter-c",
|
||||
"https://github.com/stsewd/tree-sitter-comment",
|
||||
"https://github.com/tree-sitter/tree-sitter-cpp",
|
||||
-- required by scss
|
||||
"https://github.com/tree-sitter/tree-sitter-css",
|
||||
"https://github.com/gbprod/tree-sitter-gitcommit",
|
||||
"https://github.com/tree-sitter/tree-sitter-go",
|
||||
{
|
||||
"https://github.com/ngalaiko/tree-sitter-go-template",
|
||||
lang = "gotmpl",
|
||||
},
|
||||
"https://github.com/tree-sitter/tree-sitter-html",
|
||||
"https://github.com/tree-sitter/tree-sitter-json",
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-luadoc",
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-php",
|
||||
specs = {
|
||||
{ lang = "php", location = "php" },
|
||||
{ lang = "php_only", location = "php_only" },
|
||||
},
|
||||
},
|
||||
"https://github.com/tree-sitter/tree-sitter-python",
|
||||
"https://github.com/tree-sitter/tree-sitter-rust",
|
||||
"https://github.com/serenadeai/tree-sitter-scss",
|
||||
{
|
||||
"https://github.com/derekstride/tree-sitter-sql",
|
||||
version = "gh-pages",
|
||||
},
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-svelte",
|
||||
{
|
||||
"https://github.com/tree-sitter/tree-sitter-typescript",
|
||||
specs = {
|
||||
{ lang = "typescript", location = "typescript" },
|
||||
{ lang = "tsx", location = "tsx" },
|
||||
},
|
||||
},
|
||||
{
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-xml",
|
||||
specs = {
|
||||
{ lang = "xml", location = "xml" },
|
||||
{ lang = "dtd", location = "dtd" },
|
||||
},
|
||||
},
|
||||
"https://github.com/tree-sitter-grammars/tree-sitter-yaml",
|
||||
"https://github.com/georgeharker/tree-sitter-zsh",
|
||||
},
|
||||
languages = {
|
||||
"bash",
|
||||
"c", -- builtin
|
||||
|
||||
+43
-76
@@ -29,7 +29,6 @@ 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
|
||||
@@ -89,7 +88,6 @@ local function to_pack_spec(spec)
|
||||
version = spec.version,
|
||||
data = {
|
||||
build = spec.build,
|
||||
ts_parser = spec.ts_parser,
|
||||
},
|
||||
}
|
||||
end
|
||||
@@ -112,14 +110,6 @@ local function run_build(plugin)
|
||||
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(assert(plugin.ts_parser))) do
|
||||
ts.build(plugin, p)
|
||||
end
|
||||
end
|
||||
|
||||
---@class ow.Pack.Event.Data
|
||||
---@field active boolean
|
||||
---@field kind "install" | "update" | "delete"
|
||||
@@ -129,28 +119,6 @@ end
|
||||
---@class ow.Pack.Event : vim.api.keyset.create_autocmd.callback_args
|
||||
---@field data ow.Pack.Event.Data
|
||||
|
||||
---@param plugin ow.Pack.Plugin
|
||||
---@param events ow.Pack.Event[]
|
||||
local function process_events(plugin, events)
|
||||
if not plugin.build and not plugin.ts_parser then
|
||||
return
|
||||
end
|
||||
|
||||
for _, ev in ipairs(events) do
|
||||
if
|
||||
ev.data.spec.name == plugin.name
|
||||
and ev.event == "PackChanged"
|
||||
and (ev.data.kind == "install" or ev.data.kind == "update")
|
||||
then
|
||||
if plugin.ts_parser then
|
||||
run_ts_build(plugin)
|
||||
else
|
||||
run_build(plugin)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@type uv.uv_fs_event_t?
|
||||
local watcher = nil
|
||||
---@type ow.Util.KeyedDebounceHandle<string>?
|
||||
@@ -237,56 +205,55 @@ function M.unwatch()
|
||||
end
|
||||
end
|
||||
|
||||
---@param specs (string | ow.Pack.PluginSpec)[]
|
||||
function M.setup(specs)
|
||||
---@type table<string, ow.Pack.Event[]?>
|
||||
local events = {}
|
||||
local group = vim.api.nvim_create_augroup("ow.Pack", { clear = true })
|
||||
local id = vim.api.nvim_create_autocmd(
|
||||
{ "PackChangedPre", "PackChanged" },
|
||||
{
|
||||
group = group,
|
||||
---@param ev ow.Pack.Event
|
||||
callback = function(ev)
|
||||
local name = ev.data.spec.name
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
if not events[name] then
|
||||
events[name] = {}
|
||||
end
|
||||
table.insert(events[name], ev)
|
||||
end,
|
||||
}
|
||||
)
|
||||
vim.pack.add(vim.tbl_map(to_pack_spec, specs), {
|
||||
load = function(data)
|
||||
if not data.spec.name then
|
||||
log.error("Missing name for plugin: %s", data.spec.src)
|
||||
return
|
||||
end
|
||||
local d = data.spec.data or {}
|
||||
---@type ow.Pack.Plugin
|
||||
local plugin = {
|
||||
[1] = data.spec.src,
|
||||
name = data.spec.name,
|
||||
version = data.spec.version,
|
||||
build = d.build,
|
||||
ts_parser = d.ts_parser,
|
||||
path = data.path,
|
||||
}
|
||||
table.insert(M.plugins, plugin)
|
||||
if not d.ts_parser then
|
||||
vim.cmd.packadd(plugin.name)
|
||||
---@param specs vim.pack.Spec[]
|
||||
---@param on_load fun(data: { spec: vim.pack.Spec, path: string })
|
||||
---@return table<string, true> changed names installed or updated during this call
|
||||
function M.install(specs, on_load)
|
||||
---@type table<string, true>
|
||||
local changed = {}
|
||||
local group =
|
||||
vim.api.nvim_create_augroup("ow.Pack.install", { clear = true })
|
||||
local id = vim.api.nvim_create_autocmd("PackChanged", {
|
||||
group = group,
|
||||
---@param ev ow.Pack.Event
|
||||
callback = function(ev)
|
||||
local name = ev.data.spec.name
|
||||
if
|
||||
name
|
||||
and (ev.data.kind == "install" or ev.data.kind == "update")
|
||||
then
|
||||
changed[name] = true
|
||||
end
|
||||
end,
|
||||
})
|
||||
vim.pack.add(specs, { load = on_load })
|
||||
vim.api.nvim_del_autocmd(id)
|
||||
return changed
|
||||
end
|
||||
|
||||
---@param specs (string | ow.Pack.PluginSpec)[]
|
||||
function M.setup(specs)
|
||||
local changed = M.install(vim.tbl_map(to_pack_spec, specs), function(data)
|
||||
if not data.spec.name then
|
||||
log.error("Missing name for plugin: %s", data.spec.src)
|
||||
return
|
||||
end
|
||||
local d = data.spec.data or {}
|
||||
---@type ow.Pack.Plugin
|
||||
local plugin = {
|
||||
[1] = data.spec.src,
|
||||
name = data.spec.name,
|
||||
version = data.spec.version,
|
||||
build = d.build,
|
||||
path = data.path,
|
||||
}
|
||||
table.insert(M.plugins, plugin)
|
||||
vim.cmd.packadd(plugin.name)
|
||||
end)
|
||||
|
||||
for _, plugin in ipairs(M.plugins) do
|
||||
local ev = events[plugin.name]
|
||||
if ev then
|
||||
process_events(plugin, ev)
|
||||
if plugin.build and changed[plugin.name] then
|
||||
run_build(plugin)
|
||||
end
|
||||
load(plugin.name, false)
|
||||
end
|
||||
|
||||
+108
-38
@@ -8,13 +8,33 @@ local M = {}
|
||||
---@field generate? boolean
|
||||
---@field from_json? boolean
|
||||
|
||||
---@alias ow.TS.ParserField string | ow.TS.ParserSpec | ow.TS.ParserSpec[]
|
||||
---@class ow.TS.SingleParser
|
||||
---@field [1] string
|
||||
---@field name? string
|
||||
---@field version? string | vim.VersionRange
|
||||
---@field lang? string inferred from URL (strip "tree-sitter-" prefix) if omitted
|
||||
---@field location? string
|
||||
---@field generate? boolean
|
||||
---@field from_json? boolean
|
||||
|
||||
---@param plugin ow.Pack.Plugin
|
||||
---@class ow.TS.MultiParser
|
||||
---@field [1] string
|
||||
---@field name? string
|
||||
---@field version? string | vim.VersionRange
|
||||
---@field specs ow.TS.ParserSpec[]
|
||||
|
||||
---@alias ow.TS.ParserEntry string | ow.TS.SingleParser | ow.TS.MultiParser
|
||||
|
||||
---@class ow.TS.Parser
|
||||
---@field name string
|
||||
---@field path string
|
||||
---@field specs ow.TS.ParserSpec[]
|
||||
|
||||
---@param path string
|
||||
---@param lang string
|
||||
---@return string
|
||||
local function parser_path(plugin, lang)
|
||||
return vim.fs.joinpath(plugin.path, "parser", lang .. ".so")
|
||||
local function parser_so(path, lang)
|
||||
return vim.fs.joinpath(path, "parser", lang .. ".so")
|
||||
end
|
||||
|
||||
---@param buf integer
|
||||
@@ -43,12 +63,12 @@ local function activate_open_buffers(lang)
|
||||
end
|
||||
end
|
||||
|
||||
---@param plugin ow.Pack.Plugin
|
||||
---@param parser ow.TS.Parser
|
||||
---@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)
|
||||
function M.build(parser, spec)
|
||||
local cwd = spec.location and vim.fs.joinpath(parser.path, spec.location)
|
||||
or parser.path
|
||||
local out = parser_so(parser.path, spec.lang)
|
||||
vim.fn.mkdir(vim.fs.dirname(out), "p")
|
||||
|
||||
local function on_build(r)
|
||||
@@ -105,49 +125,99 @@ function M.build(plugin, spec)
|
||||
end
|
||||
end
|
||||
|
||||
---@param field ow.TS.ParserField
|
||||
---@param pack_name string
|
||||
---@return string
|
||||
local function lang_from_name(pack_name)
|
||||
local lang = pack_name:match("^tree%-sitter%-(.+)$")
|
||||
if not lang then
|
||||
error("cannot derive lang from pack name: " .. pack_name)
|
||||
end
|
||||
return lang
|
||||
end
|
||||
|
||||
---@param entry ow.TS.ParserEntry
|
||||
---@return vim.pack.Spec
|
||||
local function entry_pack_spec(entry)
|
||||
if type(entry) == "string" then
|
||||
return { src = entry }
|
||||
end
|
||||
return {
|
||||
src = entry[1],
|
||||
name = entry.name,
|
||||
version = entry.version,
|
||||
}
|
||||
end
|
||||
|
||||
---@param entry ow.TS.ParserEntry
|
||||
---@param pack_name string fallback for lang when the entry doesn't set it
|
||||
---@return ow.TS.ParserSpec[]
|
||||
function M.normalize(field)
|
||||
if type(field) == "string" then
|
||||
return { { lang = field } }
|
||||
local function entry_specs(entry, pack_name)
|
||||
if type(entry) == "string" then
|
||||
return { { lang = lang_from_name(pack_name) } }
|
||||
end
|
||||
|
||||
if type(field) == "table" then
|
||||
if type(field.lang) == "string" then
|
||||
---@cast field ow.TS.ParserSpec
|
||||
return { field }
|
||||
end
|
||||
if type(field[1]) == "table" then
|
||||
---@cast field ow.TS.ParserSpec[]
|
||||
return field
|
||||
end
|
||||
if entry.specs then
|
||||
return entry.specs
|
||||
end
|
||||
|
||||
error("invalid ts_parser value: " .. vim.inspect(field))
|
||||
---@cast entry ow.TS.SingleParser
|
||||
return {
|
||||
{
|
||||
lang = entry.lang or lang_from_name(pack_name),
|
||||
location = entry.location,
|
||||
generate = entry.generate,
|
||||
from_json = entry.from_json,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
---@param languages string[]
|
||||
---@return string[]
|
||||
local function collect_filetypes(languages)
|
||||
local filetypes = {}
|
||||
local seen = {}
|
||||
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
|
||||
seen[ft] = true
|
||||
end
|
||||
end
|
||||
return filetypes
|
||||
return vim.tbl_keys(seen)
|
||||
end
|
||||
|
||||
---@param opts { languages: string[] }
|
||||
---@param opts { parsers: ow.TS.ParserEntry[], 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
|
||||
---@type vim.pack.Spec[]
|
||||
local pack_specs = {}
|
||||
---@type table<string, ow.TS.ParserEntry>
|
||||
local entries_by_src = {}
|
||||
for _, entry in ipairs(opts.parsers) do
|
||||
local pack_spec = entry_pack_spec(entry)
|
||||
table.insert(pack_specs, pack_spec)
|
||||
entries_by_src[pack_spec.src] = entry
|
||||
end
|
||||
|
||||
---@type ow.TS.Parser[]
|
||||
local parsers = {}
|
||||
local changed = require("pack").install(pack_specs, function(data)
|
||||
if not data.spec.name then
|
||||
log.error("Missing name for parser: %s", data.spec.src)
|
||||
return
|
||||
end
|
||||
local entry = entries_by_src[data.spec.src]
|
||||
if not entry then
|
||||
return
|
||||
end
|
||||
table.insert(parsers, {
|
||||
name = data.spec.name,
|
||||
path = data.path,
|
||||
specs = entry_specs(entry, data.spec.name),
|
||||
})
|
||||
end)
|
||||
|
||||
for _, parser in ipairs(parsers) do
|
||||
for _, spec in ipairs(parser.specs) do
|
||||
local so = parser_so(parser.path, spec.lang)
|
||||
if changed[parser.name] or not vim.uv.fs_stat(so) then
|
||||
M.build(parser, spec)
|
||||
else
|
||||
vim.treesitter.language.add(spec.lang, { path = so })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user