summaryrefslogtreecommitdiff
path: root/lua/lvim
diff options
context:
space:
mode:
authorkylo252 <[email protected]>2022-10-14 14:09:08 +0200
committerGitHub <[email protected]>2022-10-14 14:09:08 +0200
commitd433409995250f29437831d1961346821e364292 (patch)
treea0bc600dd337dc21a56ddfaa5d136112e82f4723 /lua/lvim
parentc94450633af035b5a577ac34c7817b65d0f6b5f1 (diff)
feat: latest impatient updates from upstream (#3236)
Diffstat (limited to 'lua/lvim')
-rw-r--r--lua/lvim/impatient.lua309
-rw-r--r--lua/lvim/impatient/profile.lua109
-rw-r--r--lua/lvim/utils/hooks.lua5
3 files changed, 272 insertions, 151 deletions
diff --git a/lua/lvim/impatient.lua b/lua/lvim/impatient.lua
index fe26b940..beb3862a 100644
--- a/lua/lvim/impatient.lua
+++ b/lua/lvim/impatient.lua
@@ -1,5 +1,4 @@
-- modified version from https://github.com/lewis6991/impatient.nvim
-
local vim = vim
local api = vim.api
local uv = vim.loop
@@ -7,66 +6,96 @@ local _loadfile = loadfile
local get_runtime = api.nvim__get_runtime
local fs_stat = uv.fs_stat
local mpack = vim.mpack
+local loadlib = package.loadlib
+
+local std_cache = vim.fn.stdpath "cache"
+
+local sep
+if jit.os == "Windows" then
+ sep = "\\"
+else
+ sep = "/"
+end
+
+local std_dirs = {
+ ["<APPDIR>"] = os.getenv "APPDIR",
+ ["<VIMRUNTIME>"] = os.getenv "VIMRUNTIME",
+ ["<STD_DATA>"] = vim.fn.stdpath "data",
+ ["<STD_CONFIG>"] = vim.fn.stdpath "config",
+ ["<LVIM_BASE>"] = get_lvim_base_dir(),
+ ["<LVIM_RUNTIME>"] = get_runtime_dir(),
+ ["<LVIM_CONFIG>"] = get_config_dir(),
+}
-local appdir = os.getenv "APPDIR"
+local function modpath_mangle(modpath)
+ for name, dir in pairs(std_dirs) do
+ modpath = modpath:gsub(dir, name)
+ end
+ return modpath
+end
-local M = {
+local function modpath_unmangle(modpath)
+ for name, dir in pairs(std_dirs) do
+ modpath = modpath:gsub(name, dir)
+ end
+ return modpath
+end
+
+-- Overridable by user
+local default_config = {
+ chunks = {
+ enable = true,
+ path = std_cache .. sep .. "luacache_chunks",
+ },
+ modpaths = {
+ enable = true,
+ path = std_cache .. sep .. "luacache_modpaths",
+ },
+}
+
+-- State used internally
+local default_state = {
chunks = {
cache = {},
profile = nil,
dirty = false,
- path = vim.fn.stdpath "cache" .. "/luacache_chunks",
+ get = function(self, path)
+ return self.cache[modpath_mangle(path)]
+ end,
+ set = function(self, path, chunk)
+ self.cache[modpath_mangle(path)] = chunk
+ end,
},
modpaths = {
cache = {},
profile = nil,
dirty = false,
- path = vim.fn.stdpath "cache" .. "/luacache_modpaths",
+ get = function(self, mod)
+ if self.cache[mod] then
+ return modpath_unmangle(self.cache[mod])
+ end
+ end,
+ set = function(self, mod, path)
+ self.cache[mod] = modpath_mangle(path)
+ end,
},
log = {},
}
+---@diagnostic disable-next-line: undefined-field
+local M = vim.tbl_deep_extend("keep", _G.__luacache_config or {}, default_config, default_state)
_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()
+local function 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
@@ -75,20 +104,6 @@ local function hash(modpath)
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
@@ -107,18 +122,41 @@ local function mprofile(mod, name, loader)
end
local function cprofile(path, name, loader)
+ if M.chunks.profile then
+ path = modpath_mangle(path)
+ end
profile(M.chunks, path, name, loader)
end
-local function get_runtime_file(basename, paths)
+function M.enable_profile()
+ local P = require "lvim.impatient.profile"
+
+ M.chunks.profile = {}
+ M.modpaths.profile = {}
+
+ loadlib = function(path, fun)
+ cprofile(path, "load_start")
+ local f, err = package.loadlib(path, fun)
+ cprofile(path, "load_end", "standard")
+ return f, err
+ end
+
+ P.setup(M.modpaths.profile)
+
+ api.nvim_create_user_command("LuaCacheProfile", function()
+ P.print_profile(M, std_dirs)
+ end, {})
+end
+
+local function get_runtime_file_from_parent(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, "/")
+ local parents = vim.split(basename, sep)
for i = #parents, 1, -1 do
- local parent = table.concat(vim.list_slice(parents, 1, i), "/")
- local ppath = M.modpaths.cache[parent]
+ local parent = table.concat(vim.list_slice(parents, 1, i), sep)
+ local ppath = M.modpaths:get(parent)
if ppath then
- if ppath:sub(-9) == "/init.lua" then
+ if ppath:sub(-9) == (sep .. "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
@@ -126,38 +164,71 @@ local function get_runtime_file(basename, paths)
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)
+ local modpath = ppath .. sep .. path:sub(#("lua" .. sep .. parent) + 2)
if fs_stat(modpath) then
return modpath, "cache(p)"
end
end
end
end
+end
+
+local rtp = vim.split(vim.o.rtp, ",")
- -- What Neovim does by default; slowest
- local modpath = get_runtime(paths, false, { is_lua = true })[1]
- return modpath, "standard"
+-- Make sure modpath is in rtp and that modpath is in paths.
+local function validate_modpath(modpath, paths)
+ local match = false
+ for _, p in ipairs(paths) do
+ if vim.endswith(modpath, p) then
+ match = true
+ break
+ end
+ end
+ if not match then
+ return false
+ end
+ for _, dir in ipairs(rtp) do
+ if vim.startswith(modpath, dir) then
+ return fs_stat(modpath) ~= nil
+ end
+ end
+ return false
end
local function get_runtime_file_cached(basename, paths)
+ local modpath, loader
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
+ if mp.enable then
+ local modpath_cached = mp:get(basename)
+ if modpath_cached then
+ modpath, loader = modpath_cached, "cache"
+ else
+ modpath, loader = get_runtime_file_from_parent(basename, paths)
+ end
+
+ if modpath and not validate_modpath(modpath, paths) then
+ modpath = nil
+
+ -- Invalidate
+ mp.cache[basename] = nil
+ mp.dirty = true
end
- mp.cache[basename] = nil
- mp.dirty = true
end
- local modpath, loader = get_runtime_file(basename, paths)
+ if not modpath then
+ -- What Neovim does by default; slowest
+ modpath, loader = get_runtime(paths, false, { is_lua = true })[1], "standard"
+ end
+
if modpath then
mprofile(basename, "resolve_end", loader)
- log("Creating cache for module %s", basename)
- mp.cache[basename] = modpath_mangle(modpath)
- mp.dirty = true
+ if mp.enable and loader ~= "cache" then
+ log("Creating cache for module %s", basename)
+ mp:set(basename, modpath)
+ mp.dirty = true
+ end
end
+
return modpath
end
@@ -168,8 +239,12 @@ local function extract_basename(pats)
for _, pat in ipairs(pats) do
for i, npat in ipairs {
-- Ordered by most specific
- "lua/(.*)/init%.lua",
- "lua/(.*)%.lua",
+ "lua"
+ .. sep
+ .. "(.*)"
+ .. sep
+ .. "init%.lua",
+ "lua" .. sep .. "(.*)%.lua",
} do
local m = pat:match(npat)
if i == 2 and m and m:sub(-4) == "init" then
@@ -211,8 +286,8 @@ 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" }
+ local basename = name:gsub("%.", sep)
+ local paths = { "lua" .. sep .. basename .. ".lua", "lua" .. sep .. basename .. sep .. "init.lua" }
-- Original line:
-- local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true})
@@ -239,7 +314,7 @@ local function load_package(name)
-- 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("%.", "_"))
+ local f, err = loadlib(found[1], "luaopen_" .. modname:gsub("%.", "_"))
return f or error(err)
end
return nil
@@ -248,14 +323,16 @@ end
local function load_from_cache(path)
local mc = M.chunks
- if not mc.cache[path] then
+ local cache = mc:get(path)
+
+ if not cache then
return nil, string.format("No cache for path %s", path)
end
- local mhash, codes = unpack(mc.cache[path])
+ local mhash, codes = unpack(cache)
- if mhash ~= hash(modpath_unmangle(path)) then
- mc.cache[path] = nil
+ if mhash ~= hash(path) then
+ mc:set(path)
mc.dirty = true
return nil, string.format("Stale cache for path %s", path)
end
@@ -263,7 +340,7 @@ local function load_from_cache(path)
local chunk = loadstring(codes)
if not chunk then
- mc.cache[path] = nil
+ mc:set(path)
mc.dirty = true
return nil, string.format("Cache error for path %s", path)
end
@@ -274,19 +351,23 @@ 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
+ local chunk, err
+
+ if M.chunks.enable then
+ 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)
end
- log(err)
chunk, err = _loadfile(path)
- if not err then
+ if not err and M.chunks.enable then
log("Creating cache for path %s", path)
- M.chunks.cache[modpath_mangle(path)] = { hash(path), string.dump(chunk) }
+ M.chunks:set(path, { hash(path), string.dump(chunk) })
M.chunks.dirty = true
end
@@ -296,9 +377,12 @@ end
function M.save_cache()
local function _save_cache(t)
+ if not t.enable then
+ return
+ end
if t.dirty then
log("Updating chunk cache file: %s", t.path)
- local f = io.open(t.path, "w+b")
+ local f = assert(io.open(t.path, "w+b"))
f:write(mpack.encode(t.cache))
f:flush()
t.dirty = false
@@ -308,7 +392,7 @@ function M.save_cache()
_save_cache(M.modpaths)
end
-function M.clear_cache()
+local function clear_cache()
local function _clear_cache(t)
t.cache = {}
os.remove(t.path)
@@ -319,9 +403,12 @@ end
local function init_cache()
local function _init_cache(t)
+ if not t.enable then
+ return
+ end
if fs_stat(t.path) then
log("Loading cache file %s", t.path)
- local f = io.open(t.path, "rb")
+ local f = assert(io.open(t.path, "rb"))
local ok
ok, t.cache = pcall(function()
return mpack.decode(f:read "*a")
@@ -336,6 +423,10 @@ local function init_cache()
end
end
+ if not uv.fs_stat(std_cache) then
+ vim.fn.mkdir(std_cache, "p")
+ end
+
_init_cache(M.chunks)
_init_cache(M.modpaths)
end
@@ -343,20 +434,42 @@ end
local function setup()
init_cache()
+ -- Usual package loaders
+ -- 1. package.preload
+ -- 2. vim._load_package
+ -- 3. package.path
+ -- 4. package.cpath
+ -- 5. all-in-one
+
-- Override default functions
+ for i, loader in ipairs(package.loaders) do
+ if loader == vim._load_package then
+ package.loaders[i] = load_package
+ break
+ end
+ end
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
+ local augroup = api.nvim_create_augroup("impatient", {})
+
+ api.nvim_create_user_command("LuaCacheClear", clear_cache, {})
+ api.nvim_create_user_command("LuaCacheLog", print_log, {})
+
+ api.nvim_create_autocmd({ "VimEnter", "VimLeave" }, {
+ group = augroup,
+ callback = M.save_cache,
+ })
- command! LuaCacheClear lua _G.__luacache.clear_cache()
- command! LuaCacheLog lua _G.__luacache.print_log()
- ]]
+ api.nvim_create_autocmd("OptionSet", {
+ group = augroup,
+ pattern = "runtimepath",
+ callback = function()
+ rtp = vim.split(vim.o.rtp, ",")
+ end,
+ })
end
setup()
diff --git a/lua/lvim/impatient/profile.lua b/lua/lvim/impatient/profile.lua
index 0ab04d65..2eafbbf2 100644
--- a/lua/lvim/impatient/profile.lua
+++ b/lua/lvim/impatient/profile.lua
@@ -1,12 +1,13 @@
local M = {}
-local api, uv = vim.api, vim.loop
+local sep
+if jit.os == "Windows" then
+ sep = "\\"
+else
+ sep = "/"
+end
-local std_data = vim.fn.stdpath "data"
-local std_config = vim.fn.stdpath "config"
-local vimruntime = os.getenv "VIMRUNTIME"
-local lvim_runtime = get_runtime_dir()
-local lvim_config = get_config_dir()
+local api, uv = vim.api, vim.loop
local function load_buffer(title, lines)
local bufnr = api.nvim_create_buf(false, false)
@@ -19,19 +20,6 @@ local function load_buffer(title, lines)
api.nvim_set_current_buf(bufnr)
end
-local function mod_path(path)
- if not path then
- return "?"
- end
- path = path:gsub(std_data .. "/site/pack/packer/", "<PACKER>/")
- path = path:gsub(std_data .. "/", "<STD_DATA>/")
- path = path:gsub(std_config .. "/", "<STD_CONFIG>/")
- path = path:gsub(vimruntime .. "/", "<VIMRUNTIME>/")
- path = path:gsub(lvim_runtime .. "/", "<LVIM_RUNTIME>/")
- path = path:gsub(lvim_config .. "/", "<LVIM_CONFIG>/")
- return path
-end
-
local function time_tostr(x)
if x == 0 then
return "?"
@@ -51,7 +39,7 @@ local function mem_tostr(x)
return string.format("%1.1f%s", x, unit)
end
-function M.print_profile(I)
+function M.print_profile(I, std_dirs)
local mod_profile = I.modpaths.profile
local chunk_profile = I.chunks.profile
@@ -67,42 +55,50 @@ function M.print_profile(I)
for path, m in pairs(chunk_profile) do
m.load = m.load_end - m.load_start
m.load = m.load / 1000000
- m.path = mod_path(path)
+ m.path = path or "?"
end
local module_content_width = 0
+ local unloaded = {}
+
for module, m in pairs(mod_profile) do
- m.resolve = 0
- if m.resolve_end then
- m.resolve = m.resolve_end - m.resolve_start
- m.resolve = m.resolve / 1000000
- end
+ local module_dot = module:gsub(sep, ".")
+ m.module = module_dot
- m.module = module:gsub("/", ".")
- m.loader = m.loader or m.loader_guess
+ if not package.loaded[module_dot] and not package.loaded[module] then
+ unloaded[#unloaded + 1] = m
+ else
+ m.resolve = 0
+ if m.resolve_start and m.resolve_end then
+ m.resolve = m.resolve_end - m.resolve_start
+ m.resolve = m.resolve / 1000000
+ end
- local path = I.modpaths.cache[module]
- local path_prof = chunk_profile[path]
- m.path = mod_path(path)
+ m.loader = m.loader or m.loader_guess
- if path_prof then
- chunk_profile[path] = nil
- m.load = path_prof.load
- m.ploader = path_prof.loader
- else
- m.load = 0
- m.ploader = "NA"
- end
+ local path = I.modpaths.cache[module]
+ local path_prof = chunk_profile[path]
+ m.path = path or "?"
- total_resolve = total_resolve + m.resolve
- total_load = total_load + m.load
+ if path_prof then
+ chunk_profile[path] = nil
+ m.load = path_prof.load
+ m.ploader = path_prof.loader
+ else
+ m.load = 0
+ m.ploader = "NA"
+ end
- if #module > module_content_width then
- module_content_width = #module
- end
+ total_resolve = total_resolve + m.resolve
+ total_load = total_load + m.load
+
+ if #module > module_content_width then
+ module_content_width = #module
+ end
- modules[#modules + 1] = m
+ modules[#modules + 1] = m
+ end
end
table.sort(modules, function(a, b)
@@ -181,6 +177,12 @@ function M.print_profile(I)
end
add ""
+ add "Standard directories:"
+ for alias, path in pairs(std_dirs) do
+ add(" %-12s -> %s", alias, path)
+ end
+ add ""
+
add("%s─%s┬%s─%s┐", tcwl, lcwl, tcwl, lcwl)
add(title1_fmt, "Resolve", "Load")
add("%s┬%s┼%s┬%s┼%s┬%s", tcwl, lcwl, tcwl, lcwl, mcwl, n)
@@ -207,7 +209,17 @@ function M.print_profile(I)
add(f3, p.load, p.loader, p.path)
end
add("%s┴%s┴%s", tcwl, lcwl, n)
+ end
+
+ if #unloaded > 0 then
add ""
+ add(n)
+ add "Modules which were unable to loaded"
+ add(n)
+ for _, p in ipairs(unloaded) do
+ lines[#lines + 1] = p.module
+ end
+ add(n)
end
load_buffer("Impatient Profile Report", lines)
@@ -216,13 +228,12 @@ end
M.setup = function(profile)
local _require = require
- -- luacheck: ignore 121
require = function(mod)
- local basename = mod:gsub("%.", "/")
+ local basename = mod:gsub("%.", sep)
if not profile[basename] then
profile[basename] = {}
profile[basename].resolve_start = uv.hrtime()
- profile[basename].loader_guess = "C"
+ profile[basename].loader_guess = ""
end
return _require(mod)
end
@@ -232,7 +243,7 @@ M.setup = function(profile)
for i = 1, #pl do
local l = pl[i]
pl[i] = function(mod)
- local basename = mod:gsub("%.", "/")
+ local basename = mod:gsub("%.", sep)
profile[basename].loader_guess = i == 1 and "preloader" or "loader #" .. i
return l(mod)
end
diff --git a/lua/lvim/utils/hooks.lua b/lua/lvim/utils/hooks.lua
index ce4335a9..bf0dac60 100644
--- a/lua/lvim/utils/hooks.lua
+++ b/lua/lvim/utils/hooks.lua
@@ -34,10 +34,7 @@ end
---It also forces regenerating any template ftplugin files
---Tip: Useful for clearing any outdated settings
function M.reset_cache()
- local impatient = _G.__luacache
- if impatient then
- impatient.clear_cache()
- end
+ vim.cmd [[LuaCacheClear]]
local lvim_modules = {}
for module, _ in pairs(package.loaded) do
if module:match "lvim.core" or module:match "lvim.lsp" then