mirror of
				https://github.com/folke/lazy.nvim.git
				synced 2025-11-04 00:11:06 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			576 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			576 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local Cache = require("lazy.core.cache")
 | 
						|
local Config = require("lazy.core.config")
 | 
						|
local Handler = require("lazy.core.handler")
 | 
						|
local Plugin = require("lazy.core.plugin")
 | 
						|
local Util = require("lazy.core.util")
 | 
						|
 | 
						|
---@class LazyCoreLoader
 | 
						|
local M = {}
 | 
						|
 | 
						|
local DEFAULT_PRIORITY = 50
 | 
						|
 | 
						|
---@type LazyPlugin[]
 | 
						|
M.loading = {}
 | 
						|
M.init_done = false
 | 
						|
---@type table<string,true>
 | 
						|
M.disabled_rtp_plugins = { packer_compiled = true }
 | 
						|
---@type table<string,string>
 | 
						|
M.did_ftdetect = {}
 | 
						|
M.did_handlers = false
 | 
						|
 | 
						|
function M.disable_rtp_plugin(plugin)
 | 
						|
  M.disabled_rtp_plugins[plugin] = true
 | 
						|
end
 | 
						|
 | 
						|
function M.setup()
 | 
						|
  for _, file in ipairs(Config.options.performance.rtp.disabled_plugins) do
 | 
						|
    M.disable_rtp_plugin(file)
 | 
						|
  end
 | 
						|
 | 
						|
  vim.api.nvim_create_autocmd("ColorSchemePre", {
 | 
						|
    callback = function(event)
 | 
						|
      M.colorscheme(event.match)
 | 
						|
    end,
 | 
						|
  })
 | 
						|
 | 
						|
  -- load the plugins
 | 
						|
  Plugin.load()
 | 
						|
  Handler.init()
 | 
						|
 | 
						|
  -- install missing plugins
 | 
						|
  if Config.options.install.missing then
 | 
						|
    Util.track("install")
 | 
						|
    local count = 0
 | 
						|
    while M.install_missing() do
 | 
						|
      count = count + 1
 | 
						|
      if count > 5 then
 | 
						|
        Util.error("Too many rounds of missing plugins")
 | 
						|
        break
 | 
						|
      end
 | 
						|
    end
 | 
						|
    Util.track()
 | 
						|
  end
 | 
						|
  Config.mapleader = vim.g.mapleader
 | 
						|
  Config.maplocalleader = vim.g.maplocalleader
 | 
						|
 | 
						|
  -- report any warnings & errors
 | 
						|
  Config.spec:report()
 | 
						|
 | 
						|
  -- setup handlers
 | 
						|
  Util.track("handlers")
 | 
						|
  Handler.setup()
 | 
						|
  M.did_handlers = true
 | 
						|
  Util.track()
 | 
						|
end
 | 
						|
 | 
						|
-- this will incrementally install missing plugins
 | 
						|
-- multiple rounds can happen when importing a spec from a missing plugin
 | 
						|
function M.install_missing()
 | 
						|
  for _, plugin in pairs(Config.plugins) do
 | 
						|
    local installed = plugin._.installed
 | 
						|
    local has_errors = Plugin.has_errors(plugin)
 | 
						|
 | 
						|
    if not has_errors and not (installed and not plugin._.build) then
 | 
						|
      for _, colorscheme in ipairs(Config.options.install.colorscheme) do
 | 
						|
        if colorscheme == "default" then
 | 
						|
          break
 | 
						|
        end
 | 
						|
        M.colorscheme(colorscheme)
 | 
						|
        if vim.g.colors_name or pcall(vim.cmd.colorscheme, colorscheme) then
 | 
						|
          break
 | 
						|
        end
 | 
						|
      end
 | 
						|
      Cache.reset()
 | 
						|
      require("lazy.manage").install({ wait = true, lockfile = true, clear = false })
 | 
						|
      -- remove any installed plugins from indexed, so cache will index again
 | 
						|
      for _, p in pairs(Config.plugins) do
 | 
						|
        if p._.installed then
 | 
						|
          Cache.reset(p.dir)
 | 
						|
        end
 | 
						|
      end
 | 
						|
      -- reload plugins
 | 
						|
      Plugin.load()
 | 
						|
      return true
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
-- Startup sequence
 | 
						|
-- 1. load any start plugins and do init
 | 
						|
function M.startup()
 | 
						|
  Util.track({ start = "startup" })
 | 
						|
 | 
						|
  -- load filetype.lua first since plugins might depend on that
 | 
						|
  M.source(vim.env.VIMRUNTIME .. "/filetype.lua")
 | 
						|
 | 
						|
  -- backup original rtp
 | 
						|
  local rtp = vim.opt.rtp:get() --[[@as string[] ]]
 | 
						|
 | 
						|
  -- 1. run plugin init
 | 
						|
  Util.track({ start = "init" })
 | 
						|
  for _, plugin in pairs(Config.plugins) do
 | 
						|
    if plugin.init then
 | 
						|
      Util.track({ plugin = plugin.name, init = "init" })
 | 
						|
      Util.try(function()
 | 
						|
        plugin.init(plugin)
 | 
						|
      end, "Failed to run `init` for **" .. plugin.name .. "**")
 | 
						|
      Util.track()
 | 
						|
    end
 | 
						|
  end
 | 
						|
  Util.track()
 | 
						|
 | 
						|
  -- 2. load start plugin
 | 
						|
  Util.track({ start = "start" })
 | 
						|
  for _, plugin in ipairs(M.get_start_plugins()) do
 | 
						|
    -- plugin may be loaded by another plugin in the meantime
 | 
						|
    if not plugin._.loaded then
 | 
						|
      M.load(plugin, { start = "start" })
 | 
						|
    end
 | 
						|
  end
 | 
						|
  Util.track()
 | 
						|
 | 
						|
  -- 3. load plugins from the original rtp, excluding after
 | 
						|
  Util.track({ start = "rtp plugins" })
 | 
						|
  for _, path in ipairs(rtp) do
 | 
						|
    if not path:find("after/?$") then
 | 
						|
      -- these paths don't will already have their ftdetect ran,
 | 
						|
      -- by sourcing filetype.lua above, so skip them
 | 
						|
      M.did_ftdetect[path] = path
 | 
						|
      M.packadd(path)
 | 
						|
    end
 | 
						|
  end
 | 
						|
  Util.track()
 | 
						|
 | 
						|
  -- 4. load after plugins
 | 
						|
  Util.track({ start = "after" })
 | 
						|
  for _, path in
 | 
						|
    ipairs(vim.opt.rtp:get() --[[@as string[] ]])
 | 
						|
  do
 | 
						|
    if path:find("after/?$") then
 | 
						|
      M.source_runtime(path, "plugin")
 | 
						|
    end
 | 
						|
  end
 | 
						|
  Util.track()
 | 
						|
 | 
						|
  M.init_done = true
 | 
						|
 | 
						|
  Util.track()
 | 
						|
end
 | 
						|
 | 
						|
function M.get_start_plugins()
 | 
						|
  ---@type LazyPlugin[]
 | 
						|
  local start = {}
 | 
						|
  for _, plugin in pairs(Config.plugins) do
 | 
						|
    if not plugin._.loaded and (plugin._.rtp_loaded or plugin.lazy == false) then
 | 
						|
      start[#start + 1] = plugin
 | 
						|
    end
 | 
						|
  end
 | 
						|
  table.sort(start, function(a, b)
 | 
						|
    local ap = a.priority or DEFAULT_PRIORITY
 | 
						|
    local bp = b.priority or DEFAULT_PRIORITY
 | 
						|
    return ap > bp
 | 
						|
  end)
 | 
						|
  return start
 | 
						|
end
 | 
						|
 | 
						|
---@class Loader
 | 
						|
---@param plugins string|LazyPlugin|string[]|LazyPlugin[]
 | 
						|
---@param reason {[string]:string}
 | 
						|
---@param opts? {force:boolean} when force is true, we skip the cond check
 | 
						|
function M.load(plugins, reason, opts)
 | 
						|
  ---@diagnostic disable-next-line: cast-local-type
 | 
						|
  plugins = (type(plugins) == "string" or plugins.name) and { plugins } or plugins
 | 
						|
  ---@cast plugins (string|LazyPlugin)[]
 | 
						|
 | 
						|
  for _, plugin in pairs(plugins) do
 | 
						|
    if type(plugin) == "string" then
 | 
						|
      if Config.plugins[plugin] then
 | 
						|
        plugin = Config.plugins[plugin]
 | 
						|
      elseif Config.spec.disabled[plugin] then
 | 
						|
        plugin = nil
 | 
						|
      else
 | 
						|
        Util.error("Plugin " .. plugin .. " not found")
 | 
						|
        plugin = nil
 | 
						|
      end
 | 
						|
    end
 | 
						|
    if plugin and not plugin._.loaded then
 | 
						|
      M._load(plugin, reason, opts)
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
---@param plugin LazyPlugin
 | 
						|
function M.deactivate(plugin)
 | 
						|
  if not plugin._.loaded then
 | 
						|
    return
 | 
						|
  end
 | 
						|
 | 
						|
  local main = M.get_main(plugin)
 | 
						|
 | 
						|
  if main then
 | 
						|
    Util.try(function()
 | 
						|
      local mod = require(main)
 | 
						|
      if mod.deactivate then
 | 
						|
        mod.deactivate(plugin)
 | 
						|
      end
 | 
						|
    end, "Failed to deactivate plugin " .. plugin.name)
 | 
						|
  end
 | 
						|
 | 
						|
  -- execute deactivate when needed
 | 
						|
  if plugin.deactivate then
 | 
						|
    Util.try(function()
 | 
						|
      plugin.deactivate(plugin)
 | 
						|
    end, "Failed to deactivate plugin " .. plugin.name)
 | 
						|
  end
 | 
						|
 | 
						|
  -- disable handlers
 | 
						|
  Handler.disable(plugin)
 | 
						|
 | 
						|
  -- clear plugin properties cache
 | 
						|
  plugin._.cache = nil
 | 
						|
 | 
						|
  -- remove loaded lua modules
 | 
						|
  Util.walkmods(plugin.dir .. "/lua", function(modname)
 | 
						|
    package.loaded[modname] = nil
 | 
						|
    package.preload[modname] = nil
 | 
						|
  end)
 | 
						|
 | 
						|
  -- clear vim.g.loaded_ for plugins
 | 
						|
  Util.ls(plugin.dir .. "/plugin", function(_, name, type)
 | 
						|
    if type == "file" then
 | 
						|
      vim.g["loaded_" .. name:gsub("%..*", "")] = nil
 | 
						|
    end
 | 
						|
  end)
 | 
						|
  -- set as not loaded
 | 
						|
  plugin._.loaded = nil
 | 
						|
end
 | 
						|
 | 
						|
--- reload a plugin
 | 
						|
---@param plugin LazyPlugin|string
 | 
						|
function M.reload(plugin)
 | 
						|
  if type(plugin) == "string" then
 | 
						|
    plugin = Config.plugins[plugin]
 | 
						|
  end
 | 
						|
 | 
						|
  if not plugin then
 | 
						|
    error("Plugin not found")
 | 
						|
  end
 | 
						|
 | 
						|
  local load = plugin._.loaded ~= nil
 | 
						|
  M.deactivate(plugin)
 | 
						|
 | 
						|
  -- enable handlers
 | 
						|
  Handler.enable(plugin)
 | 
						|
 | 
						|
  -- run init
 | 
						|
  if plugin.init then
 | 
						|
    Util.try(function()
 | 
						|
      plugin.init(plugin)
 | 
						|
    end, "Failed to run `init` for **" .. plugin.name .. "**")
 | 
						|
  end
 | 
						|
 | 
						|
  -- if this is a start plugin, load it now
 | 
						|
  if plugin.lazy == false then
 | 
						|
    load = true
 | 
						|
  end
 | 
						|
 | 
						|
  local events = plugin._.handlers and plugin._.handlers.event and plugin._.handlers.event or {}
 | 
						|
 | 
						|
  for _, event in pairs(events) do
 | 
						|
    if event.id:find("VimEnter") or event.id:find("UIEnter") or event.id:find("VeryLazy") then
 | 
						|
      load = true
 | 
						|
      break
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  -- reload any vimscript files for this plugin
 | 
						|
  local scripts = vim.fn.getscriptinfo()
 | 
						|
  local loaded_scripts = {}
 | 
						|
  for _, s in ipairs(scripts) do
 | 
						|
    ---@type string
 | 
						|
    local path = s.name
 | 
						|
    if
 | 
						|
      path:sub(-4) == ".vim"
 | 
						|
      and path:find(plugin.dir, 1, true) == 1
 | 
						|
      and not path:find("/plugin/", 1, true)
 | 
						|
      and not path:find("/ftplugin/", 1, true)
 | 
						|
    then
 | 
						|
      loaded_scripts[#loaded_scripts + 1] = path
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  if load then
 | 
						|
    M.load(plugin, { start = "reload" })
 | 
						|
    for _, s in ipairs(loaded_scripts) do
 | 
						|
      M.source(s)
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
---@param plugin LazyPlugin
 | 
						|
---@param reason {[string]:string}
 | 
						|
---@param opts? {force:boolean} when force is true, we skip the cond check
 | 
						|
function M._load(plugin, reason, opts)
 | 
						|
  if not plugin._.installed then
 | 
						|
    return Util.error("Plugin " .. plugin.name .. " is not installed")
 | 
						|
  end
 | 
						|
 | 
						|
  if plugin._.cond == false and not (opts and opts.force) then
 | 
						|
    return
 | 
						|
  end
 | 
						|
 | 
						|
  if not Handler.did_setup then
 | 
						|
    Util.try(function()
 | 
						|
      Handler.enable(plugin)
 | 
						|
    end, "Failed to setup handlers for " .. plugin.name)
 | 
						|
  end
 | 
						|
 | 
						|
  ---@diagnostic disable-next-line: assign-type-mismatch
 | 
						|
  plugin._.loaded = {}
 | 
						|
  for k, v in pairs(reason) do
 | 
						|
    plugin._.loaded[k] = v
 | 
						|
  end
 | 
						|
  if #M.loading > 0 then
 | 
						|
    plugin._.loaded.plugin = M.loading[#M.loading].name
 | 
						|
  elseif reason.require then
 | 
						|
    plugin._.loaded.source = Util.get_source()
 | 
						|
  end
 | 
						|
 | 
						|
  table.insert(M.loading, plugin)
 | 
						|
 | 
						|
  Util.track({ plugin = plugin.name, start = reason.start })
 | 
						|
  Handler.disable(plugin)
 | 
						|
 | 
						|
  if not plugin.virtual then
 | 
						|
    M.add_to_rtp(plugin)
 | 
						|
  end
 | 
						|
 | 
						|
  if plugin._.pkg and plugin._.pkg.source == "rockspec" then
 | 
						|
    M.add_to_luapath(plugin)
 | 
						|
  end
 | 
						|
 | 
						|
  if plugin.dependencies then
 | 
						|
    Util.try(function()
 | 
						|
      M.load(plugin.dependencies, {})
 | 
						|
    end, "Failed to load deps for " .. plugin.name)
 | 
						|
  end
 | 
						|
 | 
						|
  if not plugin.virtual then
 | 
						|
    M.packadd(plugin.dir)
 | 
						|
  end
 | 
						|
  if plugin.config or plugin.opts then
 | 
						|
    M.config(plugin)
 | 
						|
  end
 | 
						|
 | 
						|
  plugin._.loaded.time = Util.track().time
 | 
						|
  table.remove(M.loading)
 | 
						|
  vim.schedule(function()
 | 
						|
    vim.api.nvim_exec_autocmds("User", { pattern = "LazyLoad", modeline = false, data = plugin.name })
 | 
						|
    vim.api.nvim_exec_autocmds("User", { pattern = "LazyRender", modeline = false })
 | 
						|
  end)
 | 
						|
end
 | 
						|
 | 
						|
--- runs plugin config
 | 
						|
---@param plugin LazyPlugin
 | 
						|
function M.config(plugin)
 | 
						|
  local fn
 | 
						|
  if type(plugin.config) == "function" then
 | 
						|
    fn = function()
 | 
						|
      local opts = Plugin.values(plugin, "opts", false)
 | 
						|
      plugin.config(plugin, opts)
 | 
						|
    end
 | 
						|
  else
 | 
						|
    local main = M.get_main(plugin)
 | 
						|
    if main then
 | 
						|
      fn = function()
 | 
						|
        local opts = Plugin.values(plugin, "opts", false)
 | 
						|
        require(main).setup(opts)
 | 
						|
      end
 | 
						|
    else
 | 
						|
      return Util.error(
 | 
						|
        "Lua module not found for config of " .. plugin.name .. ". Please use a `config()` function instead"
 | 
						|
      )
 | 
						|
    end
 | 
						|
  end
 | 
						|
  Util.try(fn, "Failed to run `config` for " .. plugin.name)
 | 
						|
end
 | 
						|
 | 
						|
---@param plugin LazyPlugin
 | 
						|
function M.get_main(plugin)
 | 
						|
  if plugin.main then
 | 
						|
    return plugin.main
 | 
						|
  end
 | 
						|
  if plugin.name ~= "mini.nvim" and plugin.name:match("^mini%..*$") then
 | 
						|
    return plugin.name
 | 
						|
  end
 | 
						|
  local normname = Util.normname(plugin.name)
 | 
						|
  ---@type string[]
 | 
						|
  local mods = {}
 | 
						|
  for _, mod in ipairs(Cache.find("*", { all = true, rtp = false, paths = { plugin.dir } })) do
 | 
						|
    local modname = mod.modname
 | 
						|
    mods[#mods + 1] = modname
 | 
						|
    local modnorm = Util.normname(modname)
 | 
						|
    -- if we found an exact match, then use that
 | 
						|
    if modnorm == normname then
 | 
						|
      mods = { modname }
 | 
						|
      break
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  return #mods == 1 and mods[1] or nil
 | 
						|
end
 | 
						|
 | 
						|
---@param path string
 | 
						|
function M.packadd(path)
 | 
						|
  M.source_runtime(path, "plugin")
 | 
						|
  M.ftdetect(path)
 | 
						|
  if M.init_done then
 | 
						|
    M.source_runtime(path, "after/plugin")
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
---@param path string
 | 
						|
function M.ftdetect(path)
 | 
						|
  if not M.did_ftdetect[path] then
 | 
						|
    M.did_ftdetect[path] = path
 | 
						|
    vim.cmd("augroup filetypedetect")
 | 
						|
    M.source_runtime(path, "ftdetect")
 | 
						|
    vim.cmd("augroup END")
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
---@param ... string
 | 
						|
function M.source_runtime(...)
 | 
						|
  local dir = table.concat({ ... }, "/")
 | 
						|
  ---@type string[]
 | 
						|
  local files = {}
 | 
						|
  Util.walk(dir, function(path, name, t)
 | 
						|
    local ext = name:sub(-3)
 | 
						|
    name = name:sub(1, -5)
 | 
						|
    if (t == "file" or t == "link") and (ext == "lua" or ext == "vim") and not M.disabled_rtp_plugins[name] then
 | 
						|
      files[#files + 1] = path
 | 
						|
    end
 | 
						|
  end)
 | 
						|
  -- plugin files are sourced alphabetically per directory
 | 
						|
  table.sort(files)
 | 
						|
  for _, path in ipairs(files) do
 | 
						|
    M.source(path)
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
-- This does the same as runtime.c:add_pack_dir_to_rtp
 | 
						|
-- * find first after
 | 
						|
-- * find lazy pack path
 | 
						|
-- * insert right after lazy pack path or right before first after or at the end
 | 
						|
-- * insert after dir right before first after or append to the end
 | 
						|
---@param plugin LazyPlugin
 | 
						|
function M.add_to_rtp(plugin)
 | 
						|
  local rtp = vim.api.nvim_get_runtime_file("", true)
 | 
						|
  local idx_dir, idx_after
 | 
						|
 | 
						|
  for i, path in ipairs(rtp) do
 | 
						|
    if Util.is_win then
 | 
						|
      path = Util.norm(path)
 | 
						|
    end
 | 
						|
    if path == Config.me then
 | 
						|
      idx_dir = i + 1
 | 
						|
    elseif not idx_after and path:sub(-6, -1) == "/after" then
 | 
						|
      idx_after = i + 1 -- +1 to offset the insert of the plugin dir
 | 
						|
      idx_dir = idx_dir or i
 | 
						|
      break
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  table.insert(rtp, idx_dir or (#rtp + 1), plugin.dir)
 | 
						|
 | 
						|
  local after = plugin.dir .. "/after"
 | 
						|
  if vim.uv.fs_stat(after) then
 | 
						|
    table.insert(rtp, idx_after or (#rtp + 1), after)
 | 
						|
  end
 | 
						|
 | 
						|
  ---@type vim.Option
 | 
						|
  vim.opt.rtp = rtp
 | 
						|
end
 | 
						|
 | 
						|
---@param plugin LazyPlugin
 | 
						|
function M.add_to_luapath(plugin)
 | 
						|
  local root = Config.options.rocks.root .. "/" .. plugin.name
 | 
						|
  local path = root .. "/share/lua/5.1"
 | 
						|
  local cpath = root .. "/lib/lua/5.1"
 | 
						|
  local cpath2 = root .. "/lib64/lua/5.1"
 | 
						|
 | 
						|
  package.path = package.path .. ";" .. path .. "/?.lua;" .. path .. "/?/init.lua;"
 | 
						|
  package.cpath = package.cpath .. ";" .. cpath .. "/?." .. (jit.os:find("Windows") and "dll" or "so") .. ";"
 | 
						|
  package.cpath = package.cpath .. ";" .. cpath2 .. "/?." .. (jit.os:find("Windows") and "dll" or "so") .. ";"
 | 
						|
end
 | 
						|
 | 
						|
function M.source(path)
 | 
						|
  Util.track({ runtime = path })
 | 
						|
  Util.try(function()
 | 
						|
    vim.cmd("source " .. path)
 | 
						|
  end, "Failed to source `" .. path .. "`")
 | 
						|
  Util.track()
 | 
						|
end
 | 
						|
 | 
						|
function M.colorscheme(name)
 | 
						|
  if vim.tbl_contains(vim.fn.getcompletion("", "color"), name) then
 | 
						|
    return
 | 
						|
  end
 | 
						|
  for _, plugin in pairs(Config.plugins) do
 | 
						|
    if not plugin._.loaded then
 | 
						|
      for _, ext in ipairs({ "lua", "vim" }) do
 | 
						|
        local path = plugin.dir .. "/colors/" .. name .. "." .. ext
 | 
						|
        if vim.uv.fs_stat(path) then
 | 
						|
          return M.load(plugin, { colorscheme = name })
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
function M.auto_load(modname, modpath)
 | 
						|
  local plugin = Plugin.find(modpath, { fast = not M.did_handlers })
 | 
						|
  if plugin then
 | 
						|
    plugin._.rtp_loaded = true
 | 
						|
    -- don't load if:
 | 
						|
    -- * handlers haven't been setup yet
 | 
						|
    -- * we're loading specs
 | 
						|
    -- * the plugin is already loaded
 | 
						|
    if M.did_handlers and not (Plugin.loading or plugin._.loaded) then
 | 
						|
      if plugin.module == false then
 | 
						|
        error("Plugin " .. plugin.name .. " is not loaded and is configured with module=false")
 | 
						|
      end
 | 
						|
      M.load(plugin, { require = modname })
 | 
						|
      if plugin._.cond == false then
 | 
						|
        error("You're trying to load `" .. plugin.name .. "` for which `cond==false`")
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
---@param modname string
 | 
						|
function M.loader(modname)
 | 
						|
  local paths, cached = Util.get_unloaded_rtp(modname, { cache = true })
 | 
						|
  local ret = Cache.find(modname, { rtp = false, paths = paths })[1]
 | 
						|
 | 
						|
  if not ret and cached then
 | 
						|
    paths = Util.get_unloaded_rtp(modname)
 | 
						|
    ret = Cache.find(modname, { rtp = false, paths = paths })[1]
 | 
						|
  end
 | 
						|
 | 
						|
  if ret then
 | 
						|
    -- explicitly set to nil to prevent loading errors
 | 
						|
    package.loaded[modname] = nil
 | 
						|
    M.auto_load(modname, ret.modpath)
 | 
						|
    local mod = package.loaded[modname]
 | 
						|
    if type(mod) == "table" then
 | 
						|
      return function()
 | 
						|
        return mod
 | 
						|
      end
 | 
						|
    end
 | 
						|
    -- selene: allow(incorrect_standard_library_use)
 | 
						|
    return loadfile(ret.modpath, nil, nil, ret.stat)
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
return M
 |