diff options
-rw-r--r-- | lua/lvim/core/treesitter.lua | 90 |
1 files changed, 87 insertions, 3 deletions
diff --git a/lua/lvim/core/treesitter.lua b/lua/lvim/core/treesitter.lua index 9b50986e..a1bcb121 100644 --- a/lua/lvim/core/treesitter.lua +++ b/lua/lvim/core/treesitter.lua @@ -1,11 +1,27 @@ local M = {} local Log = require "lvim.core.log" -M.config = function() +function M.config() lvim.builtin.treesitter = { on_config_done = nil, - ensure_installed = {}, -- one of "all", "maintained" (parsers with maintainers), or a list of languages + + -- A list of parser names, or "all" + ensure_installed = {}, + + -- List of parsers to ignore installing (for "all") ignore_install = {}, + + -- A directory to install the parsers into. + -- By default parsers are installed to either the package dir, or the "site" dir. + -- If a custom path is used (not nil) it must be added to the runtimepath. + parser_install_dir = nil, + + -- Install parsers synchronously (only applied to `ensure_installed`) + sync_install = false, + + -- Automatically install missing parsers when entering buffer + auto_install = false, + matchup = { enable = false, -- mandatory, false will disable the whole extension -- disable = { "c", "ruby" }, -- optional, list of language that will be disabled @@ -109,7 +125,70 @@ M.config = function() } end -M.setup = function() +---@class bundledParsersOpts +---@field name_only boolean +---@field filter function + +---Retrives a list of bundled parsers paths (any parser not found in default `install_dir`) +---@param opts bundledParsersOpts +---@return string[] +local function get_parsers(opts) + opts = opts or {} + opts.filter = opts.filter or function() + return true + end + + local bundled_parsers = vim.tbl_filter(opts.filter, vim.api.nvim_get_runtime_file("parser/*.so", true)) + + if opts.name_only then + bundled_parsers = vim.tbl_map(function(parser) + return vim.fn.fnamemodify(parser, ":t:r") + end, bundled_parsers) + end + + return bundled_parsers +end + +---Checks if parser is installed with nvim-treesitter +---@param lang string +---@return boolean +local function is_installed(lang) + local configs = require "nvim-treesitter.configs" + local result = get_parsers { + filter = function(parser) + local install_dir = configs.get_parser_install_dir() + return vim.startswith(parser, install_dir) and (vim.fn.fnamemodify(parser, ":t:r") == lang) + end, + } + local parser_file = result and result[1] or "" + local stat = vim.loop.fs_stat(parser_file) + return stat and stat.type == "file" +end + +local function ensure_updated_bundled() + local configs = require "nvim-treesitter.configs" + local bundled_parsers = get_parsers { + name_only = true, + filter = function(parser) + local install_dir = configs.get_parser_install_dir() + return not vim.startswith(parser, install_dir) + end, + } + + vim.api.nvim_create_autocmd("VimEnter", { + callback = function() + local missing = vim.tbl_filter(function(parser) + return not is_installed(parser) + end, bundled_parsers) + + if #missing > 0 then + vim.cmd { cmd = "TSInstall", args = missing, bang = true } + end + end, + }) +end + +function M.setup() -- avoid running in headless mode since it's harder to detect failures if #vim.api.nvim_list_uis() == 0 then Log:debug "headless mode detected, skipping running setup for treesitter" @@ -126,9 +205,14 @@ M.setup = function() treesitter_configs.setup(opts) + ensure_updated_bundled() + if lvim.builtin.treesitter.on_config_done then lvim.builtin.treesitter.on_config_done(treesitter_configs) end end +M.get_parsers = get_parsers +M.is_installed = is_installed + return M |