-
Notifications
You must be signed in to change notification settings - Fork 337
/
loader.lua
278 lines (245 loc) · 7.3 KB
/
loader.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
local Util = require("lazy.core.util")
local Config = require("lazy.core.config")
local Handler = require("lazy.core.handler")
local M = {}
---@type LazyPlugin[]
M.loading = {}
M.init_done = false
---@type table<string,true>
M.disabled_rtp_plugins = { packer_compiled = true }
function M.setup()
-- setup handlers
Util.track("handlers")
Handler.setup()
Util.track()
for _, file in ipairs(Config.options.performance.rtp.disabled_plugins) do
M.disabled_rtp_plugins[file] = true
end
vim.api.nvim_create_autocmd("ColorSchemePre", {
callback = function(event)
M.colorscheme(event.match)
end,
})
-- autoload opt plugins
table.insert(package.loaders, M.autoload)
-- install missing plugins
if Config.options.install.missing then
Util.track("install")
for _, plugin in pairs(Config.plugins) do
if not plugin._.installed then
for _, colorscheme in ipairs(Config.options.install.colorscheme) do
if pcall(vim.cmd.colorscheme, colorscheme) then
break
end
end
require("lazy.manage").install({ wait = true })
break
end
end
Util.track()
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()
-- 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(plugin.init, "Failed to run `init` for **" .. plugin.name .. "**")
Util.track()
end
end
Util.track()
-- 2. load start plugin
Util.track({ start = "start" })
for _, plugin in pairs(Config.plugins) do
if plugin.lazy == false and not plugin._.loaded then
M.load(plugin, { start = "start" })
end
end
Util.track()
-- 3. load plugins from rtp, excluding after
Util.track({ start = "rtp plugins" })
for _, path in ipairs(rtp) do
if not path:find("after/?$") then
M.packadd(path)
end
end
Util.track()
-- 4. load after plugins
Util.track({ start = "after" })
for _, path in ipairs(vim.opt.rtp:get()) do
if path:find("after/?$") then
M.source_runtime(path, "plugin")
end
end
Util.track()
M.init_done = true
Util.track()
end
---@class Loader
---@param plugins string|LazyPlugin|string[]|LazyPlugin[]
---@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
---@cast plugins (string|LazyPlugin)[]
for _, plugin in pairs(plugins) do
plugin = type(plugin) == "string" and Config.plugins[plugin] or plugin
---@cast plugin LazyPlugin
if not plugin._.loaded then
---@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)
vim.opt.runtimepath:prepend(plugin.dir)
local after = plugin.dir .. "/after"
if vim.loop.fs_stat(after) then
vim.opt.runtimepath:append(after)
end
if plugin.dependencies then
M.load(plugin.dependencies, {})
end
M.packadd(plugin.dir)
if plugin.config then
M.config(plugin)
end
plugin._.loaded.time = Util.track().time
table.remove(M.loading)
vim.schedule(function()
vim.cmd("do User LazyRender")
end)
end
end
end
--- runs plugin config
---@param plugin LazyPlugin
function M.config(plugin)
local fn
if type(plugin.config) == "function" then
fn = plugin.config
else
local normname = Util.normname(plugin.name)
---@type table<string, string>
local mods = {}
Util.ls(plugin.dir .. "/lua", function(_, modname)
modname = modname:gsub("%.lua$", "")
mods[modname] = modname
local modnorm = Util.normname(modname)
-- if we found an exact match, then use that
if modnorm == normname then
mods = { modname }
return false
end
end)
mods = vim.tbl_values(mods)
if #mods == 1 then
fn = function()
require(mods[1]).setup(plugin.config == true and {} or plugin.config)
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 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)
vim.cmd("augroup filetypedetect")
M.source_runtime(path, "ftdetect")
vim.cmd("augroup 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
function M.source(path)
Util.track({ runtime = path })
Util.try(function()
vim.cmd("silent 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.loop.fs_stat(path) then
return M.load(plugin, { colorscheme = name })
end
end
end
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.
---@param modname string
function M.autoload(modname)
-- check if a lazy plugin should be loaded
for _, plugin in pairs(Config.plugins) do
if not (plugin._.loaded or plugin.module == false) 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 })
-- check if the module has been loaded in the meantime
if type(package.loaded[modname]) == "table" then
local mod = package.loaded[modname]
return function()
return mod
end
end
local chunk, err = loadfile(path)
return chunk or error(err)
end
end
end
end
return modname .. " not found in lazy plugins"
end
return M