|  | @@ -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
 |