refactor: deps are now loaded via a FSM
parent
a2bc77f229
commit
3732144c33
|
|
@ -1,17 +1,92 @@
|
||||||
local raw_deps = require 'sloth-flake.dependencies'
|
local raw_deps = require 'sloth-flake.dependencies'
|
||||||
|
local state_machine = require 'sloth-flake.state_machine'
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
local State = state_machine.build_states {
|
||||||
|
'NotLoaded',
|
||||||
|
'Shimed',
|
||||||
|
'Inited',
|
||||||
|
'Imported',
|
||||||
|
'Loaded',
|
||||||
|
}
|
||||||
|
|
||||||
function M.new(values)
|
function M.new(values)
|
||||||
return setmetatable({
|
local self = {
|
||||||
priv = {
|
|
||||||
init = false,
|
|
||||||
import = false,
|
|
||||||
config = false,
|
|
||||||
shim = false,
|
|
||||||
},
|
|
||||||
values = values,
|
values = values,
|
||||||
}, {
|
}
|
||||||
|
self.sm = state_machine.build(State, {
|
||||||
|
enter = {
|
||||||
|
[State.Shimed] = function()
|
||||||
|
if self.cmd then
|
||||||
|
for _, cmd in ipairs(self.cmd) do
|
||||||
|
vim.api.nvim_create_user_command(cmd, self:lazy_load_cmd(cmd), {
|
||||||
|
desc = "Sloth-flake placeholder for plugin " .. self.name,
|
||||||
|
nargs = '*',
|
||||||
|
bang = true,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.ft then
|
||||||
|
local group_id = vim.api.nvim_create_augroup(self.augroup_name, {
|
||||||
|
clear = true,
|
||||||
|
})
|
||||||
|
vim.api.nvim_create_autocmd('FileType', {
|
||||||
|
group = group_id,
|
||||||
|
pattern = self.ft,
|
||||||
|
callback = self:lazy_load_ft()
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
[State.Inited] = function()
|
||||||
|
for _, dep in ipairs(self.dependencies) do
|
||||||
|
dep:init()
|
||||||
|
end
|
||||||
|
|
||||||
|
local init = self.values.init or function() end
|
||||||
|
init()
|
||||||
|
end,
|
||||||
|
[State.Imported] = function()
|
||||||
|
for _, dep in ipairs(self.dependencies) do
|
||||||
|
dep:import()
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.is_lazy then
|
||||||
|
vim.cmd("packadd " .. self.name)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
[State.Loaded] = function()
|
||||||
|
for _, dep in ipairs(self.dependencies) do
|
||||||
|
dep:config()
|
||||||
|
end
|
||||||
|
|
||||||
|
local config = self.values.config or function() end
|
||||||
|
config()
|
||||||
|
end
|
||||||
|
},
|
||||||
|
exit = {
|
||||||
|
[State.Shimed] = function()
|
||||||
|
if self.cmd then
|
||||||
|
for _, cmd in ipairs(self.cmd) do
|
||||||
|
vim.api.nvim_del_user_command(cmd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.ft then
|
||||||
|
vim.api.nvim_del_augroup_by_name(self.augroup_name)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
events = {
|
||||||
|
shim = { from = State.NotLoaded, to = State.Shimed, },
|
||||||
|
init = { from = { State.NotLoaded, State.Shimed }, to = State.Inited, },
|
||||||
|
import = { from = State.Inited, to = State.Imported, },
|
||||||
|
config = { from = State.Imported, to = State.Loaded, },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return setmetatable(self, {
|
||||||
__index = function(self, k)
|
__index = function(self, k)
|
||||||
local fn = M[k]
|
local fn = M[k]
|
||||||
if fn then
|
if fn then
|
||||||
|
|
@ -23,7 +98,7 @@ function M.new(values)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
__newindex = function(self, k, v)
|
__newindex = function(self, k, v)
|
||||||
|
-- Ignore new values
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
@ -63,62 +138,47 @@ function M:get_is_lazy()
|
||||||
return self.values.lazy or false
|
return self.values.lazy or false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M:get_state()
|
||||||
|
return self.sm.state
|
||||||
|
end
|
||||||
|
|
||||||
function M:get_is_imported()
|
function M:get_is_imported()
|
||||||
return self.priv.import
|
return self.state >= State.Imported
|
||||||
end
|
end
|
||||||
|
|
||||||
function M:get_is_loaded()
|
function M:get_is_loaded()
|
||||||
-- last step is config, so a plugin is loaded if its config has run
|
return self.state >= State.Loaded
|
||||||
return self.priv.config
|
|
||||||
end
|
|
||||||
|
|
||||||
local function load_fn(type)
|
|
||||||
local function fn(self)
|
|
||||||
if self.priv[type] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.priv[type] = true
|
|
||||||
|
|
||||||
for _, dep in ipairs(self.dependencies) do
|
|
||||||
fn(dep)
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.values[type] ~= nil then
|
|
||||||
self.values[type]()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return fn
|
|
||||||
end
|
|
||||||
|
|
||||||
M.init = load_fn('init')
|
|
||||||
M.config = load_fn('config')
|
|
||||||
|
|
||||||
function M:import()
|
|
||||||
if self.is_imported then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.priv.import = true
|
|
||||||
|
|
||||||
for _, dep in ipairs(self.dependencies) do
|
|
||||||
dep:import()
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.is_lazy then
|
|
||||||
vim.cmd("packadd " .. self.name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:load()
|
|
||||||
self:unshim()
|
|
||||||
self:init()
|
|
||||||
self:import()
|
|
||||||
self:config()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function M:get_augroup_name()
|
function M:get_augroup_name()
|
||||||
return "Sloth-plugin-" .. self.name
|
return "Sloth-plugin-" .. self.name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M:shim()
|
||||||
|
return self.sm:shim()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:init()
|
||||||
|
return self.sm:init()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:import()
|
||||||
|
self:init()
|
||||||
|
return self.sm:import()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:config()
|
||||||
|
self:init()
|
||||||
|
self:import()
|
||||||
|
return self.sm:config()
|
||||||
|
end
|
||||||
|
|
||||||
|
function M:load()
|
||||||
|
self:init()
|
||||||
|
self:import()
|
||||||
|
return self:config()
|
||||||
|
end
|
||||||
|
|
||||||
function M:lazy_load_cmd(cmd)
|
function M:lazy_load_cmd(cmd)
|
||||||
return function(param)
|
return function(param)
|
||||||
self:load()
|
self:load()
|
||||||
|
|
@ -136,51 +196,6 @@ function M:lazy_load_ft()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function M:shim()
|
|
||||||
if self.priv.shim then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.priv.shim = true
|
|
||||||
|
|
||||||
if self.cmd then
|
|
||||||
for _, cmd in ipairs(self.cmd) do
|
|
||||||
vim.api.nvim_create_user_command(cmd, self:lazy_load_cmd(cmd), {
|
|
||||||
desc = "Sloth-flake placeholder for plugin " .. self.name,
|
|
||||||
nargs = '*',
|
|
||||||
bang = true,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.ft then
|
|
||||||
local group_id = vim.api.nvim_create_augroup(self.augroup_name, {
|
|
||||||
clear = true,
|
|
||||||
})
|
|
||||||
vim.api.nvim_create_autocmd('FileType', {
|
|
||||||
group = group_id,
|
|
||||||
pattern = self.ft,
|
|
||||||
callback = self:lazy_load_ft()
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M:unshim()
|
|
||||||
if not self.priv.shim then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
self.priv.shim = nil
|
|
||||||
|
|
||||||
if self.cmd then
|
|
||||||
for _, cmd in ipairs(self.cmd) do
|
|
||||||
vim.api.nvim_del_user_command(cmd)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.ft then
|
|
||||||
vim.api.nvim_del_augroup_by_name(self.augroup_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local deps = {}
|
local deps = {}
|
||||||
for k, v in pairs(raw_deps) do
|
for k, v in pairs(raw_deps) do
|
||||||
deps[k] = M.new(v)
|
deps[k] = M.new(v)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local stateMeta
|
||||||
|
|
||||||
|
local function are_both_states(a, b)
|
||||||
|
return a.is_state and b.is_state
|
||||||
|
end
|
||||||
|
|
||||||
|
stateMeta = {
|
||||||
|
__tostring = function(v)
|
||||||
|
return v.name
|
||||||
|
end,
|
||||||
|
__le = function(self, other)
|
||||||
|
if not are_both_states(self, other) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return self.idx <= other.idx
|
||||||
|
end,
|
||||||
|
__lt = function(self, other)
|
||||||
|
if not are_both_states(self, other) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return self.idx < other.idx
|
||||||
|
end,
|
||||||
|
__index = function(self, name)
|
||||||
|
if name == 'is_state' then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
function M.build_states(defs)
|
||||||
|
local states = {}
|
||||||
|
for i, name in ipairs(defs) do
|
||||||
|
local state = setmetatable({ idx = i, name = name }, stateMeta)
|
||||||
|
states[i] = state
|
||||||
|
states[name] = state
|
||||||
|
end
|
||||||
|
return states
|
||||||
|
end
|
||||||
|
|
||||||
|
local SM = {}
|
||||||
|
|
||||||
|
local function empty_fn()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SM:run_enter_state(state)
|
||||||
|
local enter_fn = self.defs.enter and self.defs.enter[state] or empty_fn
|
||||||
|
enter_fn(self.state)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SM:run_exit_state(state)
|
||||||
|
local enter_fn = self.defs.exit and self.defs.exit[state] or empty_fn
|
||||||
|
enter_fn(self.state)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wrap_state_array(val)
|
||||||
|
return val.is_state and { val } or val
|
||||||
|
end
|
||||||
|
|
||||||
|
local function canonicalize_event(event)
|
||||||
|
return {
|
||||||
|
from = wrap_state_array(event.from),
|
||||||
|
to = event.to,
|
||||||
|
transition = event.transition or function() end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.build(states, defs)
|
||||||
|
local machine = {
|
||||||
|
state = states[1],
|
||||||
|
defs = defs,
|
||||||
|
}
|
||||||
|
local prototype = {}
|
||||||
|
|
||||||
|
for name, infos in pairs(defs.events) do
|
||||||
|
local event = canonicalize_event(infos)
|
||||||
|
prototype[name] = function(self)
|
||||||
|
if not vim.list_contains(event.from, self.state) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local previous = self.state
|
||||||
|
self:run_exit_state(previous)
|
||||||
|
self.state = event.to
|
||||||
|
event.transition(previous, self.state)
|
||||||
|
self:run_enter_state(self.state)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local ret = setmetatable(machine, { __index = vim.tbl_extend('error', SM, prototype)})
|
||||||
|
ret:run_enter_state(states[1])
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local State = M.build_states {
|
||||||
|
'NotLoaded',
|
||||||
|
'Shimed',
|
||||||
|
'Inited',
|
||||||
|
'Imported',
|
||||||
|
'Loaded',
|
||||||
|
}
|
||||||
|
|
||||||
|
return M
|
||||||
Loading…
Reference in New Issue