@@ -10,51 +10,100 @@ local cache_path = vim.fn.stdpath("state") .. "/lazy.state"
10
10
local cache_hash
11
11
12
12
--- @alias CacheHash { mtime : { sec : number , nsec : number }, size : number }
13
- --- @alias CacheEntry { hash : CacheHash , chunk : string , used : boolean }
13
+ --- @alias CacheEntry { hash : CacheHash , modpath : string , chunk : string , used : number }
14
14
--- @type table<string,CacheEntry ? >
15
15
M .cache = {}
16
+ M .loader_idx = 2 -- 2 so preload still works
17
+ M .enabled = true
18
+ M .ttl = 3600 * 24 * 5 -- keep unused modules for up to 5 days
16
19
20
+ -- Check if we need to load this plugin
17
21
--- @param modname string
18
22
--- @param modpath string
19
- --- @return any
20
- function M .load (modname , modpath )
21
- local entry = M .cache [modname ]
22
- local hash = assert (M .hash (modpath ))
23
+ function M .check_load (modname , modpath )
24
+ if modname :sub (1 , 4 ) == " lazy" then
25
+ return
26
+ end
27
+ require (" lazy.core.loader" ).autoload (modname , modpath )
28
+ end
23
29
24
- if entry and not M .eq (entry .hash , hash ) then
25
- entry = nil
30
+ --- @param modname string
31
+ --- @return any
32
+ function M .loader (modname )
33
+ if not M .enabled then
34
+ return " lazy loader is disabled"
26
35
end
27
36
37
+ local entry = M .cache [modname ]
38
+
28
39
local chunk , err
29
40
if entry then
30
- entry .used = true
31
- chunk , err = load (entry .chunk --[[ @as string]] , " @" .. modpath , " b" )
41
+ M .check_load (modname , entry .modpath )
42
+ entry .used = os.time ()
43
+ local hash = assert (M .hash (entry .modpath ))
44
+ if M .eq (entry .hash , hash ) then
45
+ -- found in cache and up to date
46
+ chunk , err = load (entry .chunk --[[ @as string]] , " @" .. entry .modpath )
47
+ return chunk or error (err )
48
+ end
49
+ -- reload from file
50
+ entry .hash = hash
51
+ chunk , err = loadfile (entry .modpath )
32
52
else
33
- vim .schedule (function ()
34
- vim .notify (" loadfile(" .. modname .. " )" )
35
- end )
36
- chunk , err = loadfile (modpath )
37
- if chunk then
38
- M .dirty = true
39
- M .cache [modname ] = { hash = hash , chunk = string.dump (chunk ), used = true }
53
+ -- load the module and find its modpath
54
+ local modpath
55
+ chunk , modpath = M .find (modname )
56
+ if modpath then
57
+ entry = { hash = M .hash (modpath ), modpath = modpath , used = os.time () }
58
+ M .cache [modname ] = entry
40
59
end
41
60
end
42
-
43
- return chunk and chunk () or error (err )
61
+ vim .schedule (function ()
62
+ vim .notify (" loading " .. modname )
63
+ end )
64
+ if entry and chunk then
65
+ M .dirty = true
66
+ entry .chunk = string.dump (chunk )
67
+ end
68
+ return chunk or error (err )
44
69
end
45
70
46
- function M .setup ()
47
- M .load_cache ()
48
- -- preload core modules
49
- local root = vim .fn .fnamemodify (debug.getinfo (1 , " S" ).source :sub (2 ), " :p:h:h" )
50
- for _ , name in ipairs ({ " util" , " config" , " loader" , " plugin" , " handler" }) do
51
- local modname = " lazy.core." .. name
71
+ --- @param modname string
72
+ function M .find (modname )
73
+ -- update our loader position if needed
74
+ if package.loaders [M .loader_idx ] ~= M .loader then
75
+ M .loader_idx = 1
52
76
--- @diagnostic disable-next-line : no-unknown
53
- package.preload [modname ] = function ()
54
- return M .load (modname , root .. " /core/" .. name :gsub (" %." , " /" ) .. " .lua" )
77
+ for i , loader in ipairs (package.loaders ) do
78
+ if loader == M .loader then
79
+ M .loader_idx = i
80
+ break
81
+ end
55
82
end
56
83
end
57
- return M
84
+
85
+ -- find the module and its modpath
86
+ for i = M .loader_idx + 1 , # package.loaders do
87
+ --- @diagnostic disable-next-line : no-unknown
88
+ local chunk = package.loaders [i ](modname )
89
+ if type (chunk ) == " function" then
90
+ local info = debug.getinfo (chunk , " S" )
91
+ return chunk , (info .what ~= " C" and info .source :sub (2 ))
92
+ end
93
+ end
94
+ end
95
+
96
+ function M .setup ()
97
+ M .load_cache ()
98
+ table.insert (package.loaders , M .loader_idx , M .loader )
99
+
100
+ vim .api .nvim_create_autocmd (" VimEnter" , {
101
+ once = true ,
102
+ callback = function ()
103
+ -- startup done, so stop caching
104
+ M .enabled = false
105
+ end ,
106
+ })
58
107
end
59
108
60
109
--- @return CacheHash ?
71
120
function M .save_cache ()
72
121
local f = assert (uv .fs_open (cache_path , " w" , 438 ))
73
122
for modname , entry in pairs (M .cache ) do
74
- if entry .used then
123
+ if entry .used > os.time () - M . ttl then
75
124
entry .modname = modname
76
- local header = { entry .hash .size , entry .hash .mtime .sec , entry .hash .mtime .nsec , # modname , # entry .chunk }
77
- uv .fs_write (f , ffi .string (ffi .new (" const uint32_t[5]" , header ), 20 ))
125
+ local header = {
126
+ entry .hash .size ,
127
+ entry .hash .mtime .sec ,
128
+ entry .hash .mtime .nsec ,
129
+ # modname ,
130
+ # entry .chunk ,
131
+ # entry .modpath ,
132
+ entry .used ,
133
+ }
134
+ uv .fs_write (f , ffi .string (ffi .new (" const uint32_t[7]" , header ), 28 ))
78
135
uv .fs_write (f , modname )
79
136
uv .fs_write (f , entry .chunk )
137
+ uv .fs_write (f , entry .modpath )
80
138
end
81
139
end
82
140
uv .fs_close (f )
@@ -92,13 +150,20 @@ function M.load_cache()
92
150
93
151
local offset = 1
94
152
while offset + 1 < # data do
95
- local header = ffi .cast (" uint32_t*" , ffi .new (" const char[20 ]" , data :sub (offset , offset + 19 )))
96
- offset = offset + 20
153
+ local header = ffi .cast (" uint32_t*" , ffi .new (" const char[28 ]" , data :sub (offset , offset + 27 )))
154
+ offset = offset + 28
97
155
local modname = data :sub (offset , offset + header [3 ] - 1 )
98
156
offset = offset + header [3 ]
99
157
local chunk = data :sub (offset , offset + header [4 ] - 1 )
100
158
offset = offset + header [4 ]
101
- M .cache [modname ] = { hash = { size = header [0 ], mtime = { sec = header [1 ], nsec = header [2 ] } }, chunk = chunk }
159
+ local file = data :sub (offset , offset + header [5 ] - 1 )
160
+ offset = offset + header [5 ]
161
+ M .cache [modname ] = {
162
+ hash = { size = header [0 ], mtime = { sec = header [1 ], nsec = header [2 ] } },
163
+ chunk = chunk ,
164
+ modpath = file ,
165
+ used = header [6 ],
166
+ }
102
167
end
103
168
end
104
169
end
0 commit comments