Przeglądaj źródła

fix(tree-sitter): force update bundled parsers (#3475)

kylo252 2 lat temu
rodzic
commit
886e3e4da4
1 zmienionych plików z 87 dodań i 3 usunięć
  1. 87 3
      lua/lvim/core/treesitter.lua

+ 87 - 3
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