| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 | 
							- -- modified version from https://github.com/lewis6991/impatient.nvim
 
- local vim = vim
 
- local api = vim.api
 
- local uv = vim.loop
 
- local _loadfile = loadfile
 
- local get_runtime = api.nvim__get_runtime
 
- local fs_stat = uv.fs_stat
 
- local mpack = vim.mpack
 
- local appdir = os.getenv "APPDIR"
 
- local M = {
 
-   chunks = {
 
-     cache = {},
 
-     profile = nil,
 
-     dirty = false,
 
-     path = vim.fn.stdpath "cache" .. "/luacache_chunks",
 
-   },
 
-   modpaths = {
 
-     cache = {},
 
-     profile = nil,
 
-     dirty = false,
 
-     path = vim.fn.stdpath "cache" .. "/luacache_modpaths",
 
-   },
 
-   log = {},
 
- }
 
- _G.__luacache = M
 
- if not get_runtime then
 
-   -- nvim 0.5 compat
 
-   get_runtime = function(paths, all, _)
 
-     local r = {}
 
-     for _, path in ipairs(paths) do
 
-       local found = api.nvim_get_runtime_file(path, all)
 
-       for i = 1, #found do
 
-         r[#r + 1] = found[i]
 
-       end
 
-     end
 
-     return r
 
-   end
 
- end
 
- local function log(...)
 
-   M.log[#M.log + 1] = table.concat({ string.format(...) }, " ")
 
- end
 
- function M.print_log()
 
-   for _, l in ipairs(M.log) do
 
-     print(l)
 
-   end
 
- end
 
- function M.enable_profile()
 
-   local P = require "lvim.impatient.profile"
 
-   M.chunks.profile = {}
 
-   M.modpaths.profile = {}
 
-   P.setup(M.modpaths.profile)
 
-   M.print_profile = function()
 
-     P.print_profile(M)
 
-   end
 
-   vim.cmd [[command! LuaCacheProfile lua _G.__luacache.print_profile()]]
 
- end
 
- local function hash(modpath)
 
-   local stat = fs_stat(modpath)
 
-   if stat then
 
-     return stat.mtime.sec .. stat.mtime.nsec .. stat.size
 
-   end
 
-   error("Could not hash " .. modpath)
 
- end
 
- local function modpath_mangle(modpath)
 
-   if appdir then
 
-     modpath = modpath:gsub(appdir, "/$APPDIR")
 
-   end
 
-   return modpath
 
- end
 
- local function modpath_unmangle(modpath)
 
-   if appdir then
 
-     modpath = modpath:gsub("/$APPDIR", appdir)
 
-   end
 
-   return modpath
 
- end
 
- local function profile(m, entry, name, loader)
 
-   if m.profile then
 
-     local mp = m.profile
 
-     mp[entry] = mp[entry] or {}
 
-     if not mp[entry].loader and loader then
 
-       mp[entry].loader = loader
 
-     end
 
-     if not mp[entry][name] then
 
-       mp[entry][name] = uv.hrtime()
 
-     end
 
-   end
 
- end
 
- local function mprofile(mod, name, loader)
 
-   profile(M.modpaths, mod, name, loader)
 
- end
 
- local function cprofile(path, name, loader)
 
-   profile(M.chunks, path, name, loader)
 
- end
 
- local function get_runtime_file(basename, paths)
 
-   -- Look in the cache to see if we have already loaded a parent module.
 
-   -- If we have then try looking in the parents directory first.
 
-   local parents = vim.split(basename, "/")
 
-   for i = #parents, 1, -1 do
 
-     local parent = table.concat(vim.list_slice(parents, 1, i), "/")
 
-     local ppath = M.modpaths.cache[parent]
 
-     if ppath then
 
-       if ppath:sub(-9) == "/init.lua" then
 
-         ppath = ppath:sub(1, -10) -- a/b/init.lua -> a/b
 
-       else
 
-         ppath = ppath:sub(1, -5) -- a/b.lua -> a/b
 
-       end
 
-       for _, path in ipairs(paths) do
 
-         -- path should be of form 'a/b/c.lua' or 'a/b/c/init.lua'
 
-         local modpath = ppath .. "/" .. path:sub(#("lua/" .. parent) + 2)
 
-         if fs_stat(modpath) then
 
-           return modpath, "cache(p)"
 
-         end
 
-       end
 
-     end
 
-   end
 
-   -- What Neovim does by default; slowest
 
-   local modpath = get_runtime(paths, false, { is_lua = true })[1]
 
-   return modpath, "standard"
 
- end
 
- local function get_runtime_file_cached(basename, paths)
 
-   local mp = M.modpaths
 
-   if mp.cache[basename] then
 
-     local modpath = mp.cache[basename]
 
-     if fs_stat(modpath) then
 
-       mprofile(basename, "resolve_end", "cache")
 
-       return modpath
 
-     end
 
-     mp.cache[basename] = nil
 
-     mp.dirty = true
 
-   end
 
-   local modpath, loader = get_runtime_file(basename, paths)
 
-   if modpath then
 
-     mprofile(basename, "resolve_end", loader)
 
-     log("Creating cache for module %s", basename)
 
-     mp.cache[basename] = modpath_mangle(modpath)
 
-     mp.dirty = true
 
-   end
 
-   return modpath
 
- end
 
- local function extract_basename(pats)
 
-   local basename
 
-   -- Deconstruct basename from pats
 
-   for _, pat in ipairs(pats) do
 
-     for i, npat in ipairs {
 
-       -- Ordered by most specific
 
-       "lua/(.*)/init%.lua",
 
-       "lua/(.*)%.lua",
 
-     } do
 
-       local m = pat:match(npat)
 
-       if i == 2 and m and m:sub(-4) == "init" then
 
-         m = m:sub(0, -6)
 
-       end
 
-       if not basename then
 
-         if m then
 
-           basename = m
 
-         end
 
-       elseif m and m ~= basename then
 
-         -- matches are inconsistent
 
-         return
 
-       end
 
-     end
 
-   end
 
-   return basename
 
- end
 
- local function get_runtime_cached(pats, all, opts)
 
-   local fallback = false
 
-   if all or not opts or not opts.is_lua then
 
-     -- Fallback
 
-     fallback = true
 
-   end
 
-   local basename
 
-   if not fallback then
 
-     basename = extract_basename(pats)
 
-   end
 
-   if fallback or not basename then
 
-     return get_runtime(pats, all, opts)
 
-   end
 
-   return { get_runtime_file_cached(basename, pats) }
 
- end
 
- -- Copied from neovim/src/nvim/lua/vim.lua with two lines changed
 
- local function load_package(name)
 
-   local basename = name:gsub("%.", "/")
 
-   local paths = { "lua/" .. basename .. ".lua", "lua/" .. basename .. "/init.lua" }
 
-   -- Original line:
 
-   -- local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true})
 
-   local found = { get_runtime_file_cached(basename, paths) }
 
-   if #found > 0 then
 
-     local f, err = loadfile(found[1])
 
-     return f or error(err)
 
-   end
 
-   local so_paths = {}
 
-   for _, trail in ipairs(vim._so_trails) do
 
-     local path = "lua" .. trail:gsub("?", basename) -- so_trails contains a leading slash
 
-     table.insert(so_paths, path)
 
-   end
 
-   -- Original line:
 
-   -- found = vim.api.nvim__get_runtime(so_paths, false, {is_lua=true})
 
-   found = { get_runtime_file_cached(basename, so_paths) }
 
-   if #found > 0 then
 
-     -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
 
-     -- a) strip prefix up to and including the first dash, if any
 
-     -- b) replace all dots by underscores
 
-     -- c) prepend "luaopen_"
 
-     -- So "foo-bar.baz" should result in "luaopen_bar_baz"
 
-     local dash = name:find("-", 1, true)
 
-     local modname = dash and name:sub(dash + 1) or name
 
-     local f, err = package.loadlib(found[1], "luaopen_" .. modname:gsub("%.", "_"))
 
-     return f or error(err)
 
-   end
 
-   return nil
 
- end
 
- local function load_from_cache(path)
 
-   local mc = M.chunks
 
-   if not mc.cache[path] then
 
-     return nil, string.format("No cache for path %s", path)
 
-   end
 
-   local mhash, codes = unpack(mc.cache[path])
 
-   if mhash ~= hash(modpath_unmangle(path)) then
 
-     mc.cache[path] = nil
 
-     mc.dirty = true
 
-     return nil, string.format("Stale cache for path %s", path)
 
-   end
 
-   local chunk = loadstring(codes)
 
-   if not chunk then
 
-     mc.cache[path] = nil
 
-     mc.dirty = true
 
-     return nil, string.format("Cache error for path %s", path)
 
-   end
 
-   return chunk
 
- end
 
- local function loadfile_cached(path)
 
-   cprofile(path, "load_start")
 
-   local chunk, err = load_from_cache(path)
 
-   if chunk and not err then
 
-     log("Loaded cache for path %s", path)
 
-     cprofile(path, "load_end", "cache")
 
-     return chunk
 
-   end
 
-   log(err)
 
-   chunk, err = _loadfile(path)
 
-   if not err then
 
-     log("Creating cache for path %s", path)
 
-     M.chunks.cache[modpath_mangle(path)] = { hash(path), string.dump(chunk) }
 
-     M.chunks.dirty = true
 
-   end
 
-   cprofile(path, "load_end", "standard")
 
-   return chunk, err
 
- end
 
- function M.save_cache()
 
-   local function _save_cache(t)
 
-     if t.dirty then
 
-       log("Updating chunk cache file: %s", t.path)
 
-       local f = io.open(t.path, "w+b")
 
-       f:write(mpack.encode(t.cache))
 
-       f:flush()
 
-       t.dirty = false
 
-     end
 
-   end
 
-   _save_cache(M.chunks)
 
-   _save_cache(M.modpaths)
 
- end
 
- function M.clear_cache()
 
-   local function _clear_cache(t)
 
-     t.cache = {}
 
-     os.remove(t.path)
 
-   end
 
-   _clear_cache(M.chunks)
 
-   _clear_cache(M.modpaths)
 
- end
 
- local function init_cache()
 
-   local function _init_cache(t)
 
-     if fs_stat(t.path) then
 
-       log("Loading cache file %s", t.path)
 
-       local f = io.open(t.path, "rb")
 
-       local ok
 
-       ok, t.cache = pcall(function()
 
-         return mpack.decode(f:read "*a")
 
-       end)
 
-       if not ok then
 
-         log("Corrupted cache file, %s. Invalidating...", t.path)
 
-         os.remove(t.path)
 
-         t.cache = {}
 
-       end
 
-       t.dirty = not ok
 
-     end
 
-   end
 
-   _init_cache(M.chunks)
 
-   _init_cache(M.modpaths)
 
- end
 
- local function setup()
 
-   init_cache()
 
-   -- Override default functions
 
-   vim._load_package = load_package
 
-   vim.api.nvim__get_runtime = get_runtime_cached
 
-   -- luacheck: ignore 121
 
-   loadfile = loadfile_cached
 
-   vim.cmd [[
 
-     augroup impatient
 
-       autocmd VimEnter,VimLeave * lua _G.__luacache.save_cache()
 
-     augroup END
 
-     command! LuaCacheClear lua _G.__luacache.clear_cache()
 
-     command! LuaCacheLog   lua _G.__luacache.print_log()
 
-   ]]
 
- end
 
- setup()
 
- return M
 
 
  |