plugin-loader.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. local plugin_loader = {}
  2. local utils = require "lvim.utils"
  3. local Log = require "lvim.core.log"
  4. local join_paths = utils.join_paths
  5. -- we need to reuse this outside of init()
  6. local compile_path = join_paths(get_config_dir(), "plugin", "packer_compiled.lua")
  7. local snapshot_path = join_paths(get_cache_dir(), "snapshots")
  8. local default_snapshot = join_paths(get_lvim_base_dir(), "snapshots", "default.json")
  9. function plugin_loader.init(opts)
  10. opts = opts or {}
  11. local install_path = opts.install_path
  12. or join_paths(vim.fn.stdpath "data", "site", "pack", "packer", "start", "packer.nvim")
  13. local init_opts = {
  14. package_root = opts.package_root or join_paths(vim.fn.stdpath "data", "site", "pack"),
  15. compile_path = compile_path,
  16. snapshot_path = snapshot_path,
  17. log = { level = "warn" },
  18. git = {
  19. clone_timeout = 300,
  20. subcommands = {
  21. -- this is more efficient than what Packer is using
  22. fetch = "fetch --no-tags --no-recurse-submodules --update-shallow --progress",
  23. },
  24. },
  25. display = {
  26. open_fn = function()
  27. return require("packer.util").float { border = "rounded" }
  28. end,
  29. },
  30. }
  31. local in_headless = #vim.api.nvim_list_uis() == 0
  32. if in_headless then
  33. init_opts.display = nil
  34. -- NOTE: `lvim.log.level` may not be loaded from the user's config yet
  35. init_opts.log.level = lvim.log and lvim.log.level or "info"
  36. else
  37. vim.cmd [[autocmd User PackerComplete lua require('lvim.utils.hooks').run_on_packer_complete()]]
  38. end
  39. if vim.fn.empty(vim.fn.glob(install_path)) > 0 then
  40. vim.fn.system { "git", "clone", "--depth", "1", "https://github.com/wbthomason/packer.nvim", install_path }
  41. vim.cmd "packadd packer.nvim"
  42. -- IMPORTANT: we only set this the very first time to avoid constantly triggering the rollback function
  43. -- https://github.com/wbthomason/packer.nvim/blob/c576ab3f1488ee86d60fd340d01ade08dcabd256/lua/packer.lua#L998-L995
  44. init_opts.snapshot = default_snapshot
  45. end
  46. local status_ok, packer = pcall(require, "packer")
  47. if status_ok then
  48. packer.init(init_opts)
  49. end
  50. end
  51. -- packer expects a space separated list
  52. local function pcall_packer_command(cmd, kwargs)
  53. local status_ok, msg = pcall(function()
  54. require("packer")[cmd](unpack(kwargs or {}))
  55. end)
  56. if not status_ok then
  57. Log:warn(cmd .. " failed with: " .. vim.inspect(msg))
  58. Log:trace(vim.inspect(vim.fn.eval "v:errmsg"))
  59. end
  60. end
  61. function plugin_loader.cache_clear()
  62. if vim.fn.delete(compile_path) == 0 then
  63. Log:debug "deleted packer_compiled.lua"
  64. end
  65. end
  66. function plugin_loader.recompile()
  67. plugin_loader.cache_clear()
  68. pcall_packer_command "compile"
  69. if utils.is_file(compile_path) then
  70. Log:debug "generated packer_compiled.lua"
  71. end
  72. end
  73. function plugin_loader.load(configurations)
  74. Log:debug "loading plugins configuration"
  75. local packer_available, packer = pcall(require, "packer")
  76. if not packer_available then
  77. Log:warn "skipping loading plugins until Packer is installed"
  78. return
  79. end
  80. local status_ok, _ = xpcall(function()
  81. packer.reset()
  82. packer.startup(function(use)
  83. for _, plugins in ipairs(configurations) do
  84. for _, plugin in ipairs(plugins) do
  85. use(plugin)
  86. end
  87. end
  88. end)
  89. end, debug.traceback)
  90. if not status_ok then
  91. Log:warn "problems detected while loading plugins' configurations"
  92. Log:trace(debug.traceback())
  93. end
  94. end
  95. function plugin_loader.get_core_plugins()
  96. local list = {}
  97. local plugins = require "lvim.plugins"
  98. for _, item in pairs(plugins) do
  99. if not item.disable then
  100. table.insert(list, item[1]:match "/(%S*)")
  101. end
  102. end
  103. return list
  104. end
  105. function plugin_loader.sync_core_plugins(opts)
  106. opts = opts or {}
  107. Log:debug(string.format("Syncing core plugins with snapshot file [%s]", default_snapshot))
  108. local packer = require "packer"
  109. local a = require "packer.async"
  110. local async = a.sync
  111. local await = a.wait
  112. local main = a.main
  113. local core_plugins = plugin_loader.get_core_plugins()
  114. async(function()
  115. await(packer.rollback(default_snapshot, unpack(core_plugins)))
  116. :map_ok(function(ok) --NOTE: these may not be doing anything, use PackerComplete for now
  117. await(main)
  118. Log:debug(string.format("Rollback snapshot file [%s] completed", default_snapshot))
  119. if next(ok.failed) then
  120. Log:warn(string.format("Couldn't rollback %s", vim.inspect(ok.failed)))
  121. end
  122. pcall(opts.on_complete, ok)
  123. end)
  124. :map_err(function(err)
  125. await(main)
  126. Log:error(err)
  127. pcall(opts.on_error, err)
  128. end)
  129. end)()
  130. end
  131. return plugin_loader