From 575421b3fb22731a9f97370d794fe7e3c7b57f7b Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Fri, 2 Dec 2022 09:22:15 +0100 Subject: [PATCH] feat!: plugins are now autmatically loaded on require. `module=` no longer needed! --- lua/lazy/core/handler.lua | 33 ----------------------- lua/lazy/core/loader.lua | 57 ++++++++++++++++++++++++++++++++++++--- lua/lazy/core/plugin.lua | 30 +++++++++++---------- lua/lazy/core/util.lua | 16 ++++++++++- 4 files changed, 84 insertions(+), 52 deletions(-) diff --git a/lua/lazy/core/handler.lua b/lua/lazy/core/handler.lua index b65e3ba..eb040fd 100644 --- a/lua/lazy/core/handler.lua +++ b/lua/lazy/core/handler.lua @@ -6,7 +6,6 @@ local Config = require("lazy.core.config") ---@field event? string|string[] ---@field cmd? string|string[] ---@field ft? string|string[] ----@field module? string|string[] ---@field keys? string|string[] local M = {} @@ -116,36 +115,4 @@ function M.handlers.cmd(grouped) end end -function M.handlers.module(grouped) - ---@param modname string - table.insert(package.loaders, 2, function(modname) - local idx = modname:find(".", 1, true) or #modname + 1 - while idx do - local name = modname:sub(1, idx - 1) - ---@diagnostic disable-next-line: redefined-local - local plugins = grouped[name] - if plugins then - grouped[name] = nil - local reason = { require = modname } - -- almost never happens, so this does not decrease performance - if #Loader.loading == 0 then - local f = 3 - while not reason.source do - local info = debug.getinfo(f, "S") - if not info then - break - end - if info.what ~= "C" then - reason.source = info.source:sub(2) - end - f = f + 1 - end - end - Loader.load(plugins, reason) - end - idx = modname:find(".", idx + 1, true) - end - end) -end - return M diff --git a/lua/lazy/core/loader.lua b/lua/lazy/core/loader.lua index 46d08d0..077cc04 100644 --- a/lua/lazy/core/loader.lua +++ b/lua/lazy/core/loader.lua @@ -5,6 +5,7 @@ local M = {} ---@type LazyPlugin[] M.loading = {} +M.init_done = false function M.setup() -- install missing plugins @@ -25,6 +26,9 @@ function M.setup() local Handler = require("lazy.core.handler") Handler.setup() Util.track() + + -- autoload opt plugins + table.insert(package.loaders, M.autoload) end function M.init_plugins() @@ -42,6 +46,7 @@ function M.init_plugins() end Util.track() Util.track() + M.init_done = true end ---@class Loader @@ -49,7 +54,7 @@ end ---@param reason {[string]:string} function M.load(plugins, reason) ---@diagnostic disable-next-line: cast-local-type - plugins = type(plugins) == "string" or plugins.name and { plugins } or plugins + plugins = (type(plugins) == "string" or plugins.name) and { plugins } or plugins ---@cast plugins (string|LazyPlugin)[] for _, plugin in ipairs(plugins) do @@ -64,17 +69,21 @@ function M.load(plugins, reason) 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 }) - M.packadd(plugin) + + vim.opt.runtimepath:prepend(plugin.dir) if plugin.dependencies then M.load(plugin.dependencies, {}) end + M.packadd(plugin) if plugin.config then Util.try(plugin.config, "Failed to run `config` for " .. plugin.name) end @@ -90,8 +99,16 @@ end ---@param plugin LazyPlugin function M.packadd(plugin) - vim.cmd.packadd(plugin.name) - M.source_runtime(plugin, "/after/plugin") + -- FIXME: investigate further what else is needed + -- vim.cmd.packadd(plugin.name) + -- M.source_runtime(plugin, "/after/plugin") + if M.init_done then + M.source_runtime(plugin, "/plugin") + if vim.g.did_load_filetypes == 1 then + M.source_runtime(plugin, "/ftdetect") + end + M.source_runtime(plugin, "/after/plugin") + end end ---@param plugin LazyPlugin @@ -105,4 +122,36 @@ function M.source_runtime(plugin, dir) end) end +-- This loader is added as the very last one. +-- This only hits when the modname is not cached and +-- even then only once per plugin. So pretty much never. +-- +-- lazy.module will call this when loading a cached file with modpath set. +---@param modname string +---@param modpath string? +function M.autoload(modname, modpath) + -- fast return when we know the modpath + if modpath then + local plugin = require("lazy.core.plugin").find(modpath) + if plugin and not plugin._.loaded then + M.load(plugin, { require = modname }) + end + return + end + -- check if a lazy plugin should be loaded + for _, plugin in pairs(Config.plugins) do + if not plugin._.loaded then + for _, pattern in ipairs({ ".lua", "/init.lua" }) do + local path = plugin.dir .. "/lua/" .. modname:gsub("%.", "/") .. pattern + if vim.loop.fs_stat(path) then + M.load(plugin, { require = modname }) + local chunk, err = loadfile(path) + return chunk or error(err) + end + end + end + end + return modname .. " not found in unloaded opt plugins" +end + return M diff --git a/lua/lazy/core/plugin.lua b/lua/lazy/core/plugin.lua index 83975cb..68d9873 100644 --- a/lua/lazy/core/plugin.lua +++ b/lua/lazy/core/plugin.lua @@ -1,6 +1,5 @@ local Config = require("lazy.core.config") local Util = require("lazy.core.util") -local Module = require("lazy.core.module") local Handler = require("lazy.core.handler") local M = {} @@ -38,7 +37,7 @@ local M = {} ---@field dependencies? string[] ---@field _ LazyPluginState ----@alias LazySpec string|LazyPlugin|LazySpec[]|{dependencies:LazySpec} +---@alias LazySpec string|LazyPlugin|LazyPlugin[]|{dependencies:LazySpec} ---@class LazySpecLoader ---@field plugins table @@ -156,13 +155,7 @@ function M.update_state() for _, plugin in pairs(Config.plugins) do plugin._ = plugin._ or {} if plugin.lazy == nil then - local lazy = plugin.dep - or Config.options.defaults.lazy - or plugin.module - or plugin.event - or plugin.keys - or plugin.ft - or plugin.cmd + local lazy = plugin.dep or Config.options.defaults.lazy or plugin.event or plugin.keys or plugin.ft or plugin.cmd plugin.lazy = lazy and true or false end plugin.dir = Config.root .. "/" .. plugin.name @@ -193,16 +186,15 @@ function M.spec() if type(Config.spec) == "string" then -- spec is a module - local function _load(name, modpath) - local modname = Config.spec .. (name and ("." .. name) or "") + local function _load(name) + local modname = name and (Config.spec .. "." .. name) or Config.spec Util.try(function() - spec:normalize(Module.load(modname, modpath)) + spec:normalize(require(modname)) end, "Failed to load **" .. modname .. "**") end local path_plugins = vim.fn.stdpath("config") .. "/lua/" .. Config.spec:gsub("%.", "/") - local path_main = path_plugins .. (vim.loop.fs_stat(path_plugins .. ".lua") and ".lua" or "/init.lua") - _load(nil, path_main) + _load() Util.lsmod(path_plugins, _load) else -- spec is a spec @@ -228,4 +220,14 @@ function M.load() Util.track() end +-- Finds the plugin that has this path +---@param path string +function M.find(path) + if path:find(Config.root, 1, true) == 1 then + local plugin = path:sub(#Config.root + 2) + local idx = plugin:find("/", 1, true) + return idx and Config.plugins[plugin:sub(1, idx - 1)] or nil + end +end + return M diff --git a/lua/lazy/core/util.lua b/lua/lazy/core/util.lua index adaaf6c..e29029b 100644 --- a/lua/lazy/core/util.lua +++ b/lua/lazy/core/util.lua @@ -38,7 +38,7 @@ function M.try(fn, msg) if not info then break end - if info.what == "Lua" and not info.source:find("lazy.nvim") then + if info.what ~= "C" and not info.source:find("lazy.nvim") then local source = info.source:sub(2) if source:find(Config.root, 1, true) == 1 then source = source:sub(#Config.root + 1) @@ -67,6 +67,20 @@ function M.try(fn, msg) return ok and result or nil end +function M.get_source() + local f = 2 + while true do + local info = debug.getinfo(f, "S") + if not info then + break + end + if info.what ~= "C" and not info.source:find("lazy.nvim", 1, true) then + return info.source:sub(2) + end + f = f + 1 + end +end + -- Fast implementation to check if a table is a list ---@param t table function M.is_list(t)