Skip to content

Commit

Permalink
feat: lazy caching now works with functions that have upvalues
Browse files Browse the repository at this point in the history
  • Loading branch information
folke committed Nov 25, 2022
1 parent 48199f8 commit fe33e4e
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 187 deletions.
1 change: 1 addition & 0 deletions lua/lazy/core/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ M.defaults = {
---@type string[]
patterns = {},
},
interactive = true,
package_path = vim.fn.stdpath("data") .. "/site/pack/lazy",
view = {
icons = {
Expand Down
5 changes: 4 additions & 1 deletion lua/lazy/core/loader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ function M.init_plugins()
Util.track("plugin_init")
for _, name in ipairs(M.loaders.init) do
local plugin = Config.plugins[name]
if not plugin then
error(name)
end
if plugin.init then
Util.track(plugin.name)
plugin.init()
Expand Down Expand Up @@ -247,7 +250,7 @@ end
---@param plugin LazyPlugin
function M.packadd(plugin, load_start)
if plugin.opt then
vim.cmd.packadd(plugin.pack)
vim.cmd.packadd(plugin.name)
M.source_plugin_files(plugin, true)
elseif load_start then
vim.opt.runtimepath:append(plugin.dir)
Expand Down
129 changes: 58 additions & 71 deletions lua/lazy/core/state.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
local Cache = require("lazy.core.cache")
local Module = require("lazy.core.module")
local Config = require("lazy.core.config")

local M = {}

M.dirty = true

---@alias CachedPlugin LazyPlugin | {_funs: string[]}
local skip = { installed = true, loaded = true, tasks = true, dirty = true, dir = true }
local funs = { config = true, init = true, run = true }

function M.update_state(check_clean)
local Util = require("lazy.core.util")
local Config = require("lazy.core.config")

---@type table<"opt"|"start", table<string,boolean>>
local installed = { opt = {}, start = {} }
for opt, packs in pairs(installed) do
Expand All @@ -19,9 +24,11 @@ function M.update_state(check_clean)
end

for _, plugin in pairs(Config.plugins) do
plugin.opt = plugin.opt == nil and Config.options.opt or plugin.opt
local opt = plugin.opt and "opt" or "start"
plugin.installed = installed[opt][plugin.pack] == true
installed[opt][plugin.pack] = nil
plugin.dir = Config.options.package_path .. "/" .. opt .. "/" .. plugin.name
plugin.installed = installed[opt][plugin.name] == true
installed[opt][plugin.name] = nil
end

if check_clean then
Expand All @@ -44,101 +51,81 @@ function M.save()
if not M.dirty then
return
end
local Config = require("lazy.core.config")
local Plugin = require("lazy.plugin")

---@class LazyState
local state = {
---@type CachedPlugin[]
plugins = {},
---@type table<string, LazySpec>
specs = {},
loaders = require("lazy.core.loader").loaders,
config = Config.options,
}

---@alias CachedPlugin LazyPlugin | {_funcs: table<string, number|boolean>}
local skip = { installed = true, loaded = true, tasks = true, dirty = true, dir = true }
local funcount = 0

for _, plugin in pairs(Config.plugins) do
---@type CachedPlugin
local save = {}
table.insert(state.plugins, save)
---@diagnostic disable-next-line: no-unknown
for k, v in pairs(plugin) do
if type(v) == "function" then
save._funcs = save._funcs or {}
if plugin.modname then
save._funcs[k] = true
else
funcount = funcount + 1
Cache.set("cache.state.fun." .. funcount, string.dump(v))
save._funcs[k] = funcount
for _, spec in ipairs(Plugin.specs()) do
state.specs[spec.modname] = spec
for _, plugin in pairs(spec.plugins) do
---@cast plugin CachedPlugin
for k, v in pairs(plugin) do
if type(v) == "function" then
if funs[k] then
plugin._funs = plugin._funs or {}
table.insert(plugin._funs, k)
end
plugin[k] = nil
elseif skip[k] then
plugin[k] = nil
end
elseif not skip[k] then
save[k] = v
end
end
end
Cache.set("cache.state", vim.json.encode(state))
end

function M.load()
---@type boolean, LazyState
local ok, state = pcall(vim.json.decode, Cache.get("cache.state"))
if not ok then
Cache.dirty()
return false
end
local Plugin = require("lazy.plugin")
local dirty = false

local Config = require("lazy.core.config")

if not vim.deep_equal(Config.options, state.config) then
Cache.dirty()
return false
---@type boolean, LazyState?
local ok, state = pcall(vim.json.decode, Cache.get("cache.state"))
if not (ok and state and vim.deep_equal(Config.options, state.config)) then
dirty = true
state = nil
end

if Module.is_dirty(Config.options.plugins, Config.paths.main) then
return false
end
local function _loader(modname, modpath)
local spec = state and state.specs[modname]
if (not spec) or Module.is_dirty(modname, modpath) then
dirty = true
vim.schedule(function()
vim.notify("Reloading " .. modname)
end)
return Plugin.Spec.load(modname, modpath)
end
---@type LazySpec
local loaded = nil

-- plugins
for _, plugin in ipairs(state.plugins) do
Config.plugins[plugin.name] = plugin
plugin.loaded = nil
plugin.dir = Config.options.package_path .. "/" .. (plugin.opt and "opt" or "start") .. "/" .. plugin.pack
if plugin.modname then
if Module.is_dirty(plugin.modname, plugin.modpath) then
return false
end
for fun in pairs(plugin._funcs or {}) do
---@diagnostic disable-next-line: assign-type-mismatch
plugin[fun] = function(...)
local mod = Module.load(plugin.modname, plugin.modpath)
for k in pairs(plugin._funcs) do
plugin[k] = mod[k]
end
return plugin[fun](...)
end
end
elseif plugin._funcs then
for fun, id in pairs(plugin._funcs) do
local chunk = assert(Cache.get("cache.state.fun." .. id))
---@diagnostic disable-next-line: assign-type-mismatch
for name, plugin in pairs(spec.plugins) do
---@cast plugin CachedPlugin
for _, fun in ipairs(plugin._funs or {}) do
plugin[fun] = function(...)
---@diagnostic disable-next-line: assign-type-mismatch
plugin[fun] = loadstring(chunk)
return plugin[fun](...)
loaded = loaded or Plugin.Spec.load(spec.modname, spec.modpath)
return loaded.plugins[name][fun](...)
end
end
end
return spec
end
M.update_state()

-- loaders
require("lazy.core.loader").loaders = state.loaders
Plugin.load(_loader)

M.dirty = false
if state and not dirty then
require("lazy.core.loader").loaders = state.loaders
else
Cache.dirty()
end

return true
M.dirty = dirty
return not dirty
end

return M
14 changes: 14 additions & 0 deletions lua/lazy/core/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ function M.track(name, time)
end
end

-- Fast implementation to check if a table is a list
---@param t table
function M.is_list(t)
local i = 0
---@diagnostic disable-next-line: no-unknown
for _ in pairs(t) do
i = i + 1
if t[i] == nil then
return false
end
end
return true
end

function M.very_lazy()
local function _load()
vim.defer_fn(function()
Expand Down
19 changes: 3 additions & 16 deletions lua/lazy/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,7 @@ function M.setup(opts)
Util.track()

Util.track("state")
if not State.load() then
local Plugin = require("lazy.plugin")
vim.schedule(function()
Util.info("Reloading...")
end)
Util.track("reload")
Plugin.reload()
Util.track()
-- if not Config.plugins.lazy then
-- Plugin.plugin({
-- "folke/lazy.nvim",
-- opt = false,
-- })
-- end
end
State.load()
Util.track()

Util.track("install")
Expand All @@ -59,6 +45,7 @@ function M.setup(opts)
vim.cmd("do User LazyInstallPre")
require("lazy.manager").install({
wait = true,
show = Config.options.interactive,
})
break
end
Expand All @@ -75,7 +62,7 @@ function M.setup(opts)

Loader.init_plugins()

Config.plugins.lazy.loaded.time = lazy_delta
Config.plugins["lazy.nvim"].loaded.time = lazy_delta
done = true

vim.cmd("do User LazyDone")
Expand Down
5 changes: 0 additions & 5 deletions lua/lazy/manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,6 @@ function M.run(operation, opts, filter)
runner:wait(on_done)
end)

-- auto show if there are tasks running
if opts.show == nil then
require("lazy.view").show()
end

if opts.wait then
runner:wait()
end
Expand Down
Loading

0 comments on commit fe33e4e

Please sign in to comment.