From aebffc34e7af06336c8d90fc3d650faf7625098f Mon Sep 17 00:00:00 2001 From: Lazar Bulovan Date: Sat, 18 Jul 2026 18:01:32 +0200 Subject: [PATCH] fix: load compiled parser.so via vim.treesitter.language.add nvim-treesitter's :TSInstall reloads the parsers module from source (package.loaded['nvim-treesitter.parsers'] = nil), which wipes runtime config modifications. The old get_parser_configs() approach no longer works for registering custom parsers with :TSInstall. New approach: - The mason build script now compiles parser.c into parser.so during :MasonInstall tia-lsp (requires cc/gcc) - The plugin's setup_syntax finds parser.so via: 1. opts.ts_parser_path (explicit override) 2. Mason package dir (resolved from exepath('tia-lsp')) 3. ~/dev/tia-lsp/parser.so (local dev fallback) - Loads it with vim.treesitter.language.add('scl', { path = parser.so }) - Starts highlighting via vim.treesitter.start(bufnr, 'scl') in the FileType autocmd - Falls back to notifying the user if no parser.so is found - Still registers with nvim-treesitter's parsers table as best-effort for :TSInstall support (won't survive reload, but works in-session) --- lua/tia_lsp/init.lua | 81 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/lua/tia_lsp/init.lua b/lua/tia_lsp/init.lua index abe09e8..93a81e0 100644 --- a/lua/tia_lsp/init.lua +++ b/lua/tia_lsp/init.lua @@ -53,6 +53,9 @@ function M.setup(opts) pattern = "scl", callback = function(args) start_lsp(args.buf) + M.notify_parser_install_if_needed(args.buf) + -- Start tree-sitter highlighting if the parser is registered + pcall(vim.treesitter.start, args.buf, "scl") end, }) @@ -65,6 +68,8 @@ function M.setup(opts) for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do if vim.bo[bufnr].filetype == "scl" and vim.api.nvim_buf_is_loaded(bufnr) then start_lsp(bufnr) + M.notify_parser_install_if_needed(bufnr) + pcall(vim.treesitter.start, bufnr, "scl") end end @@ -78,14 +83,80 @@ function M.setup(opts) end end +-- Find a compiled tree-sitter parser (.so) for SCL. +-- Looks in: opts.ts_parser_path, mason package dir, ~/dev/tia-lsp. +-- Returns the path to parser.so, or nil if not found. +function M.find_parser_so(opts) + -- 1. Explicit path from opts + if opts.ts_parser_path and vim.fn.filereadable(opts.ts_parser_path) == 1 then + return opts.ts_parser_path + end + -- 2. Mason install: resolve exepath("tia-lsp") -> real bin -> package dir + local tia_bin = vim.fn.exepath("tia-lsp") + if tia_bin ~= "" then + local real_bin = vim.fn.resolve(vim.fn.fnamemodify(tia_bin, ":p")) + local pkg_dir = vim.fn.fnamemodify(real_bin, ":h:h") + local so = pkg_dir .. "/parser.so" + if vim.fn.filereadable(so) == 1 then + return so + end + end + -- 3. Local dev path + local dev_so = vim.fn.expand("~/dev/tia-lsp/parser.so") + if vim.fn.filereadable(dev_so) == 1 then + return dev_so + end + return nil +end + +-- Notify the user once per session if the tree-sitter parser isn't available. +local parser_notified = false + +function M.notify_parser_install_if_needed(bufnr) + if parser_notified then return end + if vim.bo[bufnr].filetype ~= "scl" then return end + local ok = pcall(vim.treesitter.get_parser, bufnr, "scl") + if ok then return end + parser_notified = true + vim.schedule(function() + local msg = "SCL: Tree-sitter parser not found. " + if vim.fn.exepath("tia-lsp") ~= "" then + msg = msg .. "Run :MasonInstall tia-lsp to install it." + else + msg = msg .. "Install tia-lsp via mason or compile parser.so manually." + end + vim.notify(msg, vim.log.levels.INFO) + end) +end + function M.setup_syntax(opts) - local has_ts, ts = pcall(require, "nvim-treesitter.parsers") - if has_ts and ts.get_parser_configs then - local ok, parser_config = pcall(ts.get_parser_configs) - if ok and parser_config then + -- Load the compiled tree-sitter parser (.so) via Neovim's built-in API. + -- This bypasses nvim-treesitter's install system, which reloads its + -- parsers module from source on :TSInstall and wipes runtime config. + local parser_so = M.find_parser_so(opts) + if parser_so then + local ok, err = pcall(vim.treesitter.language.add, "scl", { path = parser_so }) + if not ok then + vim.notify( + "SCL: Failed to load tree-sitter parser from " .. parser_so .. ": " .. tostring(err), + vim.log.levels.WARN + ) + end + end + + -- Also register with nvim-treesitter (best-effort, for :TSInstall support + -- in sessions where the user wants to install from source). + local has_ts, parsers = pcall(require, "nvim-treesitter.parsers") + if has_ts and type(parsers) == "table" then + local parser_config + if type(parsers.get_parser_configs) == "function" then + parser_config = parsers.get_parser_configs() + else + parser_config = parsers + end + if type(parser_config) == "table" then parser_config.scl = { install_info = { - -- Override via setup({ ts_parser_url = "https://your-gitea/tia-lsp.git" }). url = opts.ts_parser_url or "https://gitea.l-tech.rs/lazar/tia-lsp.git", files = { "src/parser.c" },