@@ -26,11 +26,12 @@ local cache_hash
26
26
--- @alias CacheEntry { hash : CacheHash , modpath : string , chunk : string , used : number }
27
27
--- @type table<string,CacheEntry ? >
28
28
M .cache = {}
29
- M .loader_idx = 2 -- 2 so preload still works
30
29
M .enabled = true
31
30
M .ttl = 3600 * 24 * 5 -- keep unused modules for up to 5 days
32
31
--- @type string[]
33
32
M .rtp = nil
33
+ -- selene:allow(global_usage)
34
+ M ._loadfile = _G .loadfile
34
35
35
36
-- checks wether the cached modpath is still valid
36
37
function M .check_path (modname , modpath )
@@ -65,9 +66,14 @@ function M.disable()
65
66
if not M .enabled then
66
67
return
67
68
end
68
- local idx = M .idx ()
69
- if idx then
70
- table.remove (package.loaders , idx )
69
+ -- selene:allow(global_usage)
70
+ _G .loadfile = M ._loadfile
71
+ --- @diagnostic disable-next-line : no-unknown
72
+ for i , loader in ipairs (package.loaders ) do
73
+ if loader == M .loader then
74
+ table.remove (package.loaders , i )
75
+ break
76
+ end
71
77
end
72
78
M .enabled = false
73
79
end
@@ -79,82 +85,82 @@ function M.loader(modname)
79
85
80
86
local chunk , err
81
87
if entry and M .check_path (modname , entry .modpath ) then
82
- entry .used = os.time ()
83
- local hash = M .hash (entry .modpath )
84
- if not hash then
85
- return
88
+ chunk , err = M .load (modname , entry .modpath )
89
+ else
90
+ -- find the modpath and load the module
91
+ local modpath = M .find (modname )
92
+ if modpath then
93
+ chunk , err = M .load (modname , modpath )
86
94
end
95
+ end
96
+ return chunk or (err and error (err )) or " not found in lazy cache"
97
+ end
98
+
99
+ --- @param modpath string
100
+ --- @return any , string ?
101
+ function M .loadfile (modpath )
102
+ return M .load (modpath , modpath )
103
+ end
104
+
105
+ --- @param modkey string
106
+ --- @param modpath string
107
+ --- @return function ?, string ? error_message
108
+ function M .load (modkey , modpath )
109
+ local hash = M .hash (modpath )
110
+ if not hash then
111
+ -- trigger correct error
112
+ return M ._loadfile (modpath )
113
+ end
114
+
115
+ local entry = M .cache [modkey ]
116
+ if entry then
117
+ entry .used = os.time ()
87
118
if M .eq (entry .hash , hash ) then
88
119
-- found in cache and up to date
89
- chunk , err = load (entry .chunk --[[ @as string]] , " @" .. entry .modpath )
90
- return chunk or error (err )
120
+ return loadstring (entry .chunk --[[ @as string]] , " @" .. entry .modpath )
91
121
end
92
- -- reload from file
93
- entry .hash = hash
94
- chunk , err = loadfile (entry .modpath )
95
122
else
96
- -- load the module and find its modpath
97
- local modpath
98
- chunk , modpath = M .find (modname )
99
- if modpath then
100
- entry = { hash = M .hash (modpath ), modpath = modpath , used = os.time () }
101
- M .cache [modname ] = entry
102
- end
123
+ entry = { hash = hash , modpath = modpath , used = os.time () }
124
+ M .cache [modkey ] = entry
103
125
end
126
+ entry .hash = hash
127
+
104
128
if M .debug then
105
129
vim .schedule (function ()
106
- vim .notify (" [cache:load] " .. modname )
130
+ vim .notify (" [cache:load] " .. modpath )
107
131
end )
108
132
end
109
- if entry and chunk then
133
+
134
+ local chunk , err = M ._loadfile (entry .modpath )
135
+ if chunk then
110
136
M .dirty = true
111
137
entry .chunk = string.dump (chunk )
112
138
end
113
- return chunk or error ( err )
139
+ return chunk , err
114
140
end
115
141
116
142
function M .require (modname )
117
143
return M .loader (modname )()
118
144
end
119
145
120
- function M .idx ()
121
- -- update our loader position if needed
122
- if package.loaders [M .loader_idx ] ~= M .loader then
123
- M .loader_idx = nil
124
- --- @diagnostic disable-next-line : no-unknown
125
- for i , loader in ipairs (package.loaders ) do
126
- if loader == M .loader then
127
- M .loader_idx = i
128
- break
129
- end
130
- end
131
- end
132
- return M .loader_idx
133
- end
134
-
135
146
--- @param modname string
147
+ --- @return string ?
136
148
function M .find (modname )
137
- if M .idx () then
138
- -- find the module and its modpath
139
- for i = M .loader_idx + 1 , # package.loaders do
140
- --- @diagnostic disable-next-line : no-unknown
141
- local chunk = package.loaders [i ](modname )
142
- if type (chunk ) == " function" then
143
- local info = debug.getinfo (chunk , " S" )
144
- return chunk , (info .what ~= " C" and info .source :sub (2 ))
145
- end
146
- end
147
- end
149
+ local basename = modname :gsub (" %." , " /" )
150
+ local paths = { " lua/" .. basename .. " .lua" , " lua/" .. basename .. " /init.lua" }
151
+ return vim .api .nvim__get_runtime (paths , false , { is_lua = true })[1 ]
148
152
end
149
153
154
+ -- returns the cached RTP excluding plugin dirs
150
155
function M .get_rtp ()
151
156
if not M .rtp then
152
157
M .rtp = {}
158
+ --- @type table<string,true>
153
159
local skip = {}
154
160
-- only skip plugins once Config has been setup
155
161
if package.loaded [" lazy.core.config" ] then
156
162
local Config = require (" lazy.core.config" )
157
- for _ , plugin in ipairs (Config .plugins ) do
163
+ for _ , plugin in pairs (Config .plugins ) do
158
164
if plugin .name ~= " lazy.nvim" then
159
165
skip [plugin .dir ] = true
160
166
end
@@ -173,14 +179,18 @@ end
173
179
function M .setup (opts )
174
180
-- no fancy deep extend here. just set the options
175
181
if opts and opts .performance and opts .performance .cache then
182
+ --- @diagnostic disable-next-line : no-unknown
176
183
for k , v in pairs (opts .performance .cache ) do
184
+ --- @diagnostic disable-next-line : no-unknown
177
185
M .config [k ] = v
178
186
end
179
187
end
180
188
M .debug = opts and opts .debug
181
189
182
190
M .load_cache ()
183
- table.insert (package.loaders , M .loader_idx , M .loader )
191
+ table.insert (package.loaders , 2 , M .loader )
192
+ -- selene:allow(global_usage)
193
+ _G .loadfile = M .loadfile
184
194
185
195
-- reset rtp when it changes
186
196
vim .api .nvim_create_autocmd (" OptionSet" , {
0 commit comments