236 lines
6.2 KiB
Lua
236 lines
6.2 KiB
Lua
local Path = require "cave.path"
|
|
local Util = require "cave.util"
|
|
local Meta = require "cave.meta"
|
|
local Context = require "cave.context"
|
|
local Config = require "cave.config"
|
|
local Log = require "cave.log"
|
|
local ClassLogger = require "cave.log.class_logger"
|
|
|
|
local resession = require "resession"
|
|
|
|
local validate = Meta.validate
|
|
local Str = Meta.String
|
|
|
|
local CONFIG_SCRIPT_TEMPLATE = [[
|
|
---@type cave.Config.Builder
|
|
local function configure(config)
|
|
end
|
|
return configure
|
|
]]
|
|
|
|
---@class cave.Project : cave.Context
|
|
---@field config_dir cave.Path
|
|
---@field config_script cave.Path
|
|
---@field config_dir_watch number
|
|
---@field config cave.Config?
|
|
---@field templates overseer.TemplateDefinition[]
|
|
---@field template_order table<string,number>
|
|
local Project = Meta.derive("Project", Context)
|
|
|
|
Project.log = ClassLogger.new(Project)
|
|
|
|
---@param dir cave.Path
|
|
---@param name string
|
|
---@param uuid string
|
|
function Project:init(dir, name, uuid)
|
|
Context.init(self, dir, name, uuid)
|
|
self.config_dir = Path.stdpath("data", "cave", "project", uuid):to_absolute() --[[@as cave.Path]]
|
|
self.config_script = self.config_dir / "config.lua"
|
|
self.templates = {}
|
|
self.template_order = {}
|
|
end
|
|
|
|
---@param dir cave.Path
|
|
---@param name string
|
|
---@param uuid string
|
|
---@return cave.Project
|
|
function Project.new(dir, name, uuid)
|
|
validate { dir = { dir, Path }, name = { name, Str }, uuid = { uuid, Str } }
|
|
local project = setmetatable({}, Project)
|
|
project:init(dir, name, uuid)
|
|
return project
|
|
end
|
|
|
|
---@return boolean
|
|
function Project:session_exists()
|
|
for _, session in pairs(resession.list()) do
|
|
if session == self.uuid then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
---@return boolean
|
|
function Project:session_active() return resession.get_current() == self.uuid end
|
|
|
|
function Project:load_session()
|
|
local log = Project.log:call()
|
|
if self:session_exists() then
|
|
resession.load(self.uuid, { silence_errors = true, notify = false })
|
|
else
|
|
Util.close_all_buffers()
|
|
self:save_session()
|
|
end
|
|
|
|
if not self:session_active() then log:warn "project session activation failed" end
|
|
log:ok()
|
|
end
|
|
|
|
function Project:save_session()
|
|
local log = Project.log:call()
|
|
|
|
resession.save(self.uuid, { attach = true, notify = false })
|
|
|
|
if not self:session_exists() then return log:err "session wasn't created" end
|
|
log:ok()
|
|
end
|
|
|
|
function Project:delete_session()
|
|
local log = Project.log:call()
|
|
|
|
if not self:session_exists() then return log:ok() end
|
|
resession.delete(self.uuid)
|
|
|
|
if self:session_exists() then log:err "session wasn't deleted" end
|
|
log:ok()
|
|
end
|
|
|
|
function Project:init_config_dir()
|
|
local log = Project.log:call()
|
|
|
|
if not self.config_dir:is_dir() and not self.config_dir:mkdir(Path.const.o755, true) then
|
|
return log:err("config dir (%q) creation failed\n%s", self.config_dir, self.config_dir.error_msg)
|
|
end
|
|
|
|
if not self.config_script:exists() and not self.config_script:io_write(CONFIG_SCRIPT_TEMPLATE) then
|
|
return log:err("config file (%q) creation failed\n%s", self.config_script, self.config_script.error_msg)
|
|
end
|
|
|
|
log:ok()
|
|
end
|
|
|
|
function Project:load_config()
|
|
local log = Project.log:call()
|
|
|
|
self.config = nil
|
|
|
|
if not self.config_script:is_file() then
|
|
return log:err("config script (%q) missing", self.config_script)
|
|
end
|
|
|
|
local chunk, err = loadfile(self.config_script:tostring())
|
|
if chunk == nil then return log:err("config script loading failed\n%s", err) end
|
|
|
|
local chunk_ok, chunk_res = pcall(chunk)
|
|
if not chunk_ok then return log:err("config script failed\n%s", chunk_res) end
|
|
|
|
local res_type = type(chunk_res)
|
|
if res_type ~= "function" then return log:err("config script returned %s instead of function", res_type) end
|
|
|
|
local config_factory = Config.Factory.new(self)
|
|
local configure_ok, configure_res = pcall(chunk_res --[[@as cave.Config.Builder]], config_factory)
|
|
if not configure_ok then return log:err("configuring failed\n%s", configure_res) end
|
|
|
|
local build_config_ok, build_config_res = pcall(Config.Factory.build, config_factory)
|
|
if not build_config_ok then return log:err("building config failed\n%s", configure_res) end
|
|
|
|
self.config = build_config_res
|
|
log:ok()
|
|
end
|
|
|
|
function Project:load_templates()
|
|
local log = Project.log:call()
|
|
self.templates = self.config and self.config:templates() or {}
|
|
|
|
local task_order = {}
|
|
for _, template in ipairs(self.templates) do
|
|
local priority = self.template_order[template.name]
|
|
if priority ~= nil then
|
|
template.priority = priority
|
|
task_order[template.name] = priority
|
|
end
|
|
end
|
|
self.template_order = task_order
|
|
log:ok()
|
|
end
|
|
|
|
---@param name string
|
|
function Project:on_template_run(name)
|
|
validate { name = { name, Str } }
|
|
local log = Project.log:call()
|
|
local priority = -os.clock()
|
|
for _, template in ipairs(self.templates) do
|
|
if template.name == name then
|
|
template.priority = priority
|
|
self.template_order[name] = priority
|
|
break
|
|
end
|
|
end
|
|
log:ok()
|
|
end
|
|
|
|
function Project:watch_config_dir()
|
|
local log = Project.log:call()
|
|
|
|
if self.config_dir_watch == nil then
|
|
self.config_dir_watch = vim.api.nvim_create_autocmd("BufWritePost", {
|
|
callback = vim.schedule_wrap(function(event)
|
|
if self.config_dir_watch == nil then return end
|
|
if Path.new(event.match):to_absolute():is_relative_to(self.config_dir) then self:reload() end
|
|
end),
|
|
})
|
|
end
|
|
|
|
log:ok()
|
|
end
|
|
|
|
function Project:unwatch_config_dir()
|
|
local log = Project.log:call()
|
|
|
|
if self.config_dir_watch then
|
|
vim.api.nvim_del_autocmd(self.config_dir_watch)
|
|
self.config_dir_watch = nil
|
|
end
|
|
|
|
log:ok()
|
|
end
|
|
|
|
function Project:reload()
|
|
self:load_config()
|
|
self:load_templates()
|
|
end
|
|
|
|
function Project:open()
|
|
local log = Project.log:call()
|
|
|
|
self:load_session()
|
|
self:init_config_dir()
|
|
self:reload()
|
|
self:watch_config_dir()
|
|
|
|
log:ok()
|
|
end
|
|
|
|
function Project:close()
|
|
local log = Project.log:call()
|
|
|
|
self:unwatch_config_dir()
|
|
Util.save_all_buffers()
|
|
self:save_session()
|
|
|
|
log:ok()
|
|
end
|
|
|
|
---@param new_name string
|
|
function Project:rename(new_name)
|
|
validate { new_name = { new_name, Str } }
|
|
local log = Project.log:call("%q", new_name)
|
|
if self.name == new_name then return log:ok() end
|
|
|
|
self.name = new_name
|
|
if self.config ~= nil then self:reload() end
|
|
|
|
log:ok()
|
|
end
|
|
|
|
return Project
|