Initial commit
This commit is contained in:
7
.stylua.toml
Normal file
7
.stylua.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
column_width = 110
|
||||
line_endings = "Unix"
|
||||
indent_type = "Spaces"
|
||||
indent_width = 2
|
||||
quote_style = "AutoPreferDouble"
|
||||
call_parentheses = "None"
|
||||
collapse_simple_statement = "Always"
|
||||
75
lua/cave/config.lua
Normal file
75
lua/cave/config.lua
Normal file
@@ -0,0 +1,75 @@
|
||||
local Meta = require "cave.meta"
|
||||
local Python = require "cave.python"
|
||||
local Context = require "cave.context"
|
||||
|
||||
local Map = Meta.Map
|
||||
local Optional = Meta.Optional
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
local Table = Meta.Table
|
||||
|
||||
---@class cave.Config
|
||||
---@field python_interpreters table<string,cave.Python.Interpreter>
|
||||
local Config = Meta.derive "Config"
|
||||
|
||||
---@return overseer.TemplateDefinition[]
|
||||
function Config:templates()
|
||||
local templates = {}
|
||||
for _, python_interpreter in pairs(self.python_interpreters) do
|
||||
vim.list_extend(templates, python_interpreter:templates())
|
||||
end
|
||||
return templates
|
||||
end
|
||||
|
||||
---@class cave.Config.Factory : cave.Context
|
||||
---@field python_interpreters_ cave.Python.Interpreter.Factory[]
|
||||
---@field context_ cave.Context
|
||||
local Factory = Meta.derive("Config.Factory", Context)
|
||||
|
||||
function Factory:init(context)
|
||||
Context.init(self, context.dir, context.name, context.uuid)
|
||||
self.python_interpreters_ = {}
|
||||
self.context_ = context
|
||||
end
|
||||
|
||||
---@param context cave.Context
|
||||
---@return cave.Config.Factory
|
||||
function Factory.new(context)
|
||||
validate { context = { context, Context } }
|
||||
local factory = setmetatable({}, Factory)
|
||||
factory:init(context)
|
||||
return factory
|
||||
end
|
||||
|
||||
---@return cave.Python.Interpreter.Factory[]
|
||||
function Factory:get_python_interpreters() return self.python_interpreters_ end
|
||||
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:python()
|
||||
local python_interpreter = Python.Interpreter.Factory.new(self.context_)
|
||||
table.insert(self.python_interpreters_, python_interpreter)
|
||||
return python_interpreter
|
||||
end
|
||||
|
||||
---@param config cave.Config
|
||||
function Factory:init_config(config)
|
||||
config.python_interpreters = {}
|
||||
for _, python_interpreter_factory in pairs(self:get_python_interpreters()) do
|
||||
local python_interpreter = python_interpreter_factory:build()
|
||||
assert(config.python_interpreters[python_interpreter.id] == nil)
|
||||
config.python_interpreters[python_interpreter.id] = python_interpreter
|
||||
end
|
||||
end
|
||||
|
||||
---@return cave.Config
|
||||
function Factory:build()
|
||||
local config = setmetatable({}, Config)
|
||||
self:init_config(config)
|
||||
return config
|
||||
end
|
||||
|
||||
---@alias cave.Config.Builder fun(config: cave.Config.Factory)
|
||||
|
||||
Config.Factory = Factory
|
||||
|
||||
return Config
|
||||
30
lua/cave/context.lua
Normal file
30
lua/cave/context.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
local Meta = require "cave.meta"
|
||||
local Path = require "cave.path"
|
||||
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
|
||||
---@class cave.Context
|
||||
---@field dir cave.Path
|
||||
---@field name string
|
||||
---@field uuid string
|
||||
local Context = Meta.derive "Context"
|
||||
|
||||
---@param dir cave.Path
|
||||
---@param name string
|
||||
---@param uuid string
|
||||
function Context:init(dir, name, uuid)
|
||||
validate { dir = { dir, Path }, uuid = { uuid, Str }, name = { name, Str } }
|
||||
self.dir = dir
|
||||
self.name = name
|
||||
self.uuid = uuid
|
||||
end
|
||||
|
||||
---@return string
|
||||
function Context:tostring()
|
||||
return ("Context(dir=%q, name=%q, uuid=%q)"):format(self.dir, self.name, self.uuid)
|
||||
end
|
||||
|
||||
Context.__tostring = Context.tostring
|
||||
|
||||
return Context
|
||||
23
lua/cave/enum.lua
Normal file
23
lua/cave/enum.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local Meta = require "cave.meta"
|
||||
local validate = Meta.validate
|
||||
local Map = Meta.Map
|
||||
local Str = Meta.String
|
||||
|
||||
---@class cave.Enum
|
||||
local Enum = {}
|
||||
Enum.__index = Enum
|
||||
|
||||
---@param tbl table<string, string>
|
||||
---@param name string
|
||||
function Enum.new(tbl, name)
|
||||
validate {
|
||||
tbl = { tbl, Map(Str, Str) },
|
||||
name = { name, Str },
|
||||
}
|
||||
for key, value in pairs(tbl) do
|
||||
assert(key == value)
|
||||
end
|
||||
setmetatable(tbl, { __meta = Meta.Enum(tbl, name) })
|
||||
end
|
||||
|
||||
return Enum
|
||||
62
lua/cave/env.lua
Normal file
62
lua/cave/env.lua
Normal file
@@ -0,0 +1,62 @@
|
||||
local Meta = require "cave.meta"
|
||||
local Util = require "cave.util"
|
||||
local Context = require "cave.context"
|
||||
local ClassLogger = require "cave.log.class_logger"
|
||||
|
||||
local validate = Meta.validate
|
||||
local Optional = Meta.Optional
|
||||
|
||||
---@class cave.Env
|
||||
---@field vars table<string, string>
|
||||
---@field on_update_cbs function[]
|
||||
local Env = Meta.derive "Env"
|
||||
Env.log = ClassLogger.new(Env)
|
||||
|
||||
---@param context cave.Context?
|
||||
---@return cave.Env
|
||||
function Env:new(context)
|
||||
local env = setmetatable({}, Env)
|
||||
env.vars = {}
|
||||
local dir, name, uuid
|
||||
if context then
|
||||
dir, name, uuid = tostring(context.dir), context.name, context.uuid
|
||||
else
|
||||
dir, name, uuid = nil, nil, nil
|
||||
end
|
||||
vim.fn.setenv("NVIM_PROJECT_DIR", dir)
|
||||
vim.fn.setenv("NVIM_PROJECT_NAME", name)
|
||||
vim.fn.setenv("NVIM_PROJECT_UUID", uuid)
|
||||
for _, entry in ipairs(vim.fn.systemlist { "nvim_env" }) do
|
||||
local split_idx = entry:find "="
|
||||
assert(split_idx ~= nil)
|
||||
env.vars[entry:sub(1, split_idx - 1)] = entry:sub(split_idx + 1, -1)
|
||||
end
|
||||
return env
|
||||
end
|
||||
|
||||
---@param context cave.Context?
|
||||
function Env:update(context)
|
||||
validate { context = { context, Optional(Context) } }
|
||||
local log = Env.log:call("%s", context)
|
||||
|
||||
local new_env = Env:new(context)
|
||||
local env_var_diff = Util.tbl_diff(self.vars, new_env.vars)
|
||||
|
||||
for name, value in pairs(env_var_diff.added) do
|
||||
vim.fn.setenv(name, value)
|
||||
end
|
||||
for name, values in pairs(env_var_diff.modified) do
|
||||
vim.fn.setenv(name, values.new)
|
||||
end
|
||||
for name, _ in pairs(env_var_diff.removed) do
|
||||
vim.fn.setenv(name, nil)
|
||||
end
|
||||
|
||||
self.vars = new_env.vars
|
||||
|
||||
-- vim.g.python3_host_prog = get_python3_host_prog()
|
||||
|
||||
log:ok("environment variables changed:\n%s", vim.inspect(env_var_diff))
|
||||
end
|
||||
|
||||
return Env
|
||||
51
lua/cave/init.lua
Normal file
51
lua/cave/init.lua
Normal file
@@ -0,0 +1,51 @@
|
||||
---@class cave
|
||||
local cave = {}
|
||||
cave.Path = require "cave.path"
|
||||
cave.Util = require "cave.util"
|
||||
|
||||
cave.manager = require("cave.manager").new()
|
||||
|
||||
function cave.load_project_from_cwd()
|
||||
local manager = cave.manager
|
||||
local workspaces = require "workspaces"
|
||||
local Path = cave.Path
|
||||
local cwd = Path.cwd()
|
||||
for project_name, project in pairs(manager:get_projects()) do
|
||||
if project.dir:samefile(cwd) then workspaces.open(project_name) end
|
||||
end
|
||||
end
|
||||
|
||||
function cave.setup()
|
||||
vim.api.nvim_create_user_command(
|
||||
"ProjectAdd",
|
||||
function(cmd_opts) cave.manager:add_project(unpack(cmd_opts.fargs)) end,
|
||||
{
|
||||
desc = "Add a project (dir?, name?)",
|
||||
nargs = "*",
|
||||
complete = "file",
|
||||
}
|
||||
)
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
"ProjectRemove",
|
||||
function(cmd_opts) cave.manager:remove_project(unpack(cmd_opts.fargs)) end,
|
||||
{
|
||||
desc = "Remove a project (name?)",
|
||||
nargs = 1,
|
||||
complete = function(lead) return cave.manager:project_name_complete(lead) end,
|
||||
}
|
||||
)
|
||||
vim.api.nvim_create_user_command(
|
||||
"ProjectRename",
|
||||
function(cmd_opts) cave.manager:rename_project(unpack(cmd_opts.fargs)) end,
|
||||
{
|
||||
desc = "Rename a project. (old_name, new_name)",
|
||||
nargs = "+",
|
||||
complete = function(lead) return cave.manager:project_name_complete(lead) end,
|
||||
}
|
||||
)
|
||||
|
||||
vim.schedule(cave.load_project_from_cwd)
|
||||
end
|
||||
|
||||
return cave
|
||||
46
lua/cave/log/class_logger.lua
Normal file
46
lua/cave/log/class_logger.lua
Normal file
@@ -0,0 +1,46 @@
|
||||
local Logger = require "cave.log.logger"
|
||||
local FunctionLogger = require "cave.log.function_logger"
|
||||
local Meta = require "cave.meta"
|
||||
|
||||
local validate = Meta.validate
|
||||
local Table = Meta.Table
|
||||
|
||||
---@class cave.ClassLogger : cave.Logger
|
||||
local ClassLogger = Meta.derive("ClassLogger", Logger)
|
||||
|
||||
---@param cls_name string
|
||||
function ClassLogger:init(cls_name)
|
||||
local prefix = cls_name
|
||||
Logger.init(self, prefix)
|
||||
end
|
||||
|
||||
---@param cls_mt table
|
||||
---@return cave.ClassLogger
|
||||
function ClassLogger.new(cls_mt)
|
||||
validate { cls_mt = { cls_mt, Table } }
|
||||
local cls_name = Meta.like(cls_mt).repr
|
||||
local logger = setmetatable({}, ClassLogger)
|
||||
logger:init(cls_name)
|
||||
return logger
|
||||
end
|
||||
|
||||
---@param args_fmt string?
|
||||
---@param ... any
|
||||
---@return cave.FunctionLogger
|
||||
function ClassLogger:call(args_fmt, ...)
|
||||
local dbg_info
|
||||
local fn_name
|
||||
for l = 2, 1, -1 do
|
||||
dbg_info = debug.getinfo(l, "n")
|
||||
fn_name = dbg_info.name
|
||||
if fn_name then break end
|
||||
end
|
||||
if dbg_info.namewhat == "method" then
|
||||
fn_name = self.prefix .. ":" .. fn_name
|
||||
elseif dbg_info.namewhat == "field" then
|
||||
fn_name = self.prefix .. "." .. fn_name
|
||||
end
|
||||
return FunctionLogger.new(fn_name, args_fmt, ...):call()
|
||||
end
|
||||
|
||||
return ClassLogger
|
||||
65
lua/cave/log/function_logger.lua
Normal file
65
lua/cave/log/function_logger.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
local Log = require "cave.log"
|
||||
local Meta = require "cave.meta"
|
||||
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
local Optional = Meta.Optional
|
||||
|
||||
---@class cave.FunctionLogger
|
||||
---@field fn_repr string
|
||||
local FunctionLogger = Meta.derive "FuncLogger"
|
||||
|
||||
---@param fn_name string
|
||||
---@param args_fmt string?
|
||||
---@param ... any
|
||||
function FunctionLogger:init(fn_name, args_fmt, ...)
|
||||
local args_repr = (args_fmt and args_fmt:format(...)) or ""
|
||||
self.fn_repr = ("%s(%s)"):format(fn_name, args_repr)
|
||||
end
|
||||
|
||||
---@param fn_name string
|
||||
---@param args_fmt string?
|
||||
---@param ... any
|
||||
---@return cave.FunctionLogger
|
||||
function FunctionLogger.new(fn_name, args_fmt, ...)
|
||||
validate { fn_name = { fn_name, Str }, args_fmt = { args_fmt, Optional(Str) } }
|
||||
local logger = setmetatable({}, FunctionLogger)
|
||||
logger:init(fn_name, args_fmt, ...)
|
||||
return logger
|
||||
end
|
||||
|
||||
---@return cave.FunctionLogger
|
||||
function FunctionLogger:call()
|
||||
Log.dbg("> %s", self.fn_repr)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param err_fmt string?
|
||||
---@param ... any
|
||||
function FunctionLogger:err(err_fmt, ...)
|
||||
validate { err = { err_fmt, Optional(Str) } }
|
||||
local res_msg = "err"
|
||||
if err_fmt ~= nil then res_msg = res_msg .. " " .. err_fmt:format(...) end
|
||||
Log.err(("< %s - %s"):format(self.fn_repr, res_msg))
|
||||
end
|
||||
|
||||
--
|
||||
---@param warn_fmt string?
|
||||
---@param ... any
|
||||
function FunctionLogger:warn(warn_fmt, ...)
|
||||
validate { err = { warn_fmt, Optional(Str) } }
|
||||
local res_msg = "warn"
|
||||
if warn_fmt ~= nil then res_msg = res_msg .. " " .. warn_fmt:format(...) end
|
||||
Log.err(("~ %s - %s"):format(self.fn_repr, res_msg))
|
||||
end
|
||||
|
||||
---@param res_fmt string?
|
||||
---@param ... any
|
||||
function FunctionLogger:ok(res_fmt, ...)
|
||||
validate { results = { res_fmt, Optional(Str) } }
|
||||
local res_msg = "ok"
|
||||
if res_fmt ~= nil then res_msg = res_msg .. " " .. res_fmt:format(...) end
|
||||
Log.dbg(("< %s - %s"):format(self.fn_repr, res_msg))
|
||||
end
|
||||
|
||||
return FunctionLogger
|
||||
25
lua/cave/log/init.lua
Normal file
25
lua/cave/log/init.lua
Normal file
@@ -0,0 +1,25 @@
|
||||
---@class cave.Log
|
||||
local Log = {}
|
||||
|
||||
---@param msg string
|
||||
---@param level integer
|
||||
---@param ...? any
|
||||
local function notify(msg, level, ...) vim.notify(msg:format(...), level, { title = "cave.nvim" }) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Log.dbg(msg, ...) notify(msg, vim.log.levels.DEBUG, ...) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Log.err(msg, ...) notify(msg, vim.log.levels.ERROR, ...) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Log.inf(msg, ...) notify(msg, vim.log.levels.INFO, ...) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Log.warn(msg, ...) notify(msg, vim.log.levels.WARN, ...) end
|
||||
|
||||
return Log
|
||||
39
lua/cave/log/logger.lua
Normal file
39
lua/cave/log/logger.lua
Normal file
@@ -0,0 +1,39 @@
|
||||
local Log = require "cave.log"
|
||||
local Meta = require "cave.meta"
|
||||
|
||||
local validate = Meta.validate
|
||||
local Str = Meta.String
|
||||
|
||||
---@class cave.Logger
|
||||
---@field prefix string
|
||||
local Logger = Meta.derive "Logger"
|
||||
|
||||
---@param prefix string
|
||||
function Logger:init(prefix) self.prefix = prefix end
|
||||
|
||||
---@param prefix string
|
||||
---@return cave.Logger
|
||||
function Logger.new(prefix)
|
||||
validate { prefix = { prefix, Str } }
|
||||
local logger = setmetatable({}, Logger)
|
||||
logger:init(prefix)
|
||||
return logger
|
||||
end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Logger:dbg(msg, ...) Log.dbg(self.prefix .. msg, ...) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Logger:err(msg, ...) Log.err(self.prefix .. msg, ...) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Logger:inf(msg, ...) Log.inf(self.prefix .. msg, ...) end
|
||||
|
||||
---@param msg string
|
||||
---@param ...? any
|
||||
function Logger:warn(msg, ...) Log.warn(self.prefix .. msg, ...) end
|
||||
|
||||
return Logger
|
||||
188
lua/cave/manager.lua
Normal file
188
lua/cave/manager.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
local Env = require "cave.env"
|
||||
local Meta = require "cave.meta"
|
||||
local Path = require "cave.path"
|
||||
local Project = require "cave.project"
|
||||
local Util = require "cave.util"
|
||||
local ClassLogger = require "cave.log.class_logger"
|
||||
local TemplateProvider = require "cave.template_provider"
|
||||
|
||||
local workspaces = require "workspaces"
|
||||
local overseer = require "overseer"
|
||||
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
local Optional = Meta.Optional
|
||||
|
||||
---@class cave.Manager
|
||||
---@field project? cave.Project
|
||||
---@field env cave.Env
|
||||
---@field template_provider cave.TemplateProvider
|
||||
local Manager = Meta.derive "Manager"
|
||||
Manager.log = ClassLogger.new(Manager)
|
||||
|
||||
function Manager:init()
|
||||
self.env = Env:new()
|
||||
---@return overseer.TemplateDefinition[]
|
||||
local function project_templates() return self.project and self.project.templates or {} end
|
||||
self.template_provider = TemplateProvider.new("cave.nvim", project_templates)
|
||||
overseer.register_template(self.template_provider)
|
||||
---@param task_defn overseer.TaskDefinition
|
||||
---@param _ overseer.TaskUtil
|
||||
local function on_template_run(task_defn, _)
|
||||
local name = task_defn.name
|
||||
if name == nil or self.project == nil then return end
|
||||
self.project:on_template_run(name)
|
||||
end
|
||||
|
||||
overseer.add_template_hook(nil, on_template_run)
|
||||
end
|
||||
|
||||
---@return cave.Manager
|
||||
function Manager.new()
|
||||
local manager = setmetatable({}, Manager)
|
||||
manager:init()
|
||||
return manager
|
||||
end
|
||||
|
||||
---@return table<string, cave.Project>
|
||||
function Manager:get_projects()
|
||||
local projects = {}
|
||||
if self.project ~= nil then projects[self.project.name] = self.project end
|
||||
for _, ws in pairs(workspaces.get()) do
|
||||
local project = Project.new(Path.new(ws.path), ws.name, ws.custom)
|
||||
if projects[project.name] == nil then projects[project.name] = project end
|
||||
end
|
||||
return projects
|
||||
end
|
||||
|
||||
---@param lead string
|
||||
---@return string[]
|
||||
function Manager:project_name_complete(lead)
|
||||
validate { lead = { lead, Str } }
|
||||
local projects = self:get_projects()
|
||||
local project_names = {}
|
||||
for project_name, _ in pairs(projects) do
|
||||
if vim.startswith(project_name, lead) then table.insert(project_names, project_name) end
|
||||
end
|
||||
return project_names
|
||||
end
|
||||
|
||||
---@param lead string
|
||||
---@return string[]
|
||||
function Manager:project_dir_complete(lead)
|
||||
validate { lead = { lead, Str } }
|
||||
local projects = self:get_projects()
|
||||
local project_dirs = {}
|
||||
for _, project in pairs(projects) do
|
||||
local project_dir = tostring(project.dir)
|
||||
if vim.startswith(project_dir, lead) then table.insert(project_dirs, project_dir) end
|
||||
end
|
||||
return project_dirs
|
||||
end
|
||||
|
||||
---@param dir string?
|
||||
---@param name string?
|
||||
function Manager:add_project(dir, name)
|
||||
validate { dir = { dir, Optional(Str) }, name = { name, Optional(Str) } }
|
||||
local log = Manager.log:call("dir=%q, name=%s", dir, name and ("%q"):format(name) or "nil")
|
||||
|
||||
local project_dir = Path.new(dir or Path.cwd())
|
||||
assert(project_dir:is_absolute())
|
||||
local project_name = name or project_dir:basename()
|
||||
local project_uuid = Util.generate_uuid()
|
||||
if not project_dir:is_dir() then return log:err("%q is not a directory", project_dir) end
|
||||
|
||||
local projects = self:get_projects()
|
||||
local project_exists = projects[project_name] ~= nil
|
||||
if project_exists then return log:err("project with name %q already exists", project_name) end
|
||||
|
||||
local project = Project.new(project_dir, project_name, project_uuid)
|
||||
|
||||
workspaces.add(tostring(project.dir), project.name)
|
||||
workspaces.set_custom(project.name, project.uuid)
|
||||
|
||||
log:ok()
|
||||
end
|
||||
|
||||
---@param name string
|
||||
function Manager:remove_project(name)
|
||||
validate { name = { name, Str } }
|
||||
local log = Manager.log:call("name=%q", name)
|
||||
|
||||
local projects = self:get_projects()
|
||||
local project = projects[name]
|
||||
if project == nil then return log:err "projectdoesn't exist" end
|
||||
|
||||
if project == self.project then self:close_project() end
|
||||
|
||||
workspaces.remove(name)
|
||||
|
||||
log:ok()
|
||||
end
|
||||
|
||||
---@param old_name string
|
||||
---@param new_name string
|
||||
function Manager:rename_project(old_name, new_name)
|
||||
validate { new_name = { new_name, Str }, old_name = { old_name, Str } }
|
||||
local log = Manager.log:call("old_name=%q, new_name=%q", old_name, new_name)
|
||||
|
||||
if new_name == old_name then return log:ok() end
|
||||
|
||||
local projects = self:get_projects()
|
||||
local project = projects[old_name]
|
||||
if project == nil then return log:err "project with old name doesn't exist" end
|
||||
if projects[new_name] ~= nil then return log:err "project with new name already exists" end
|
||||
|
||||
project:rename(new_name)
|
||||
|
||||
if project == self.project then self.env:update() end
|
||||
|
||||
workspaces.rename(old_name, new_name)
|
||||
|
||||
log:ok()
|
||||
end
|
||||
|
||||
---@param name string
|
||||
function Manager:open_project(name)
|
||||
validate { name = { name, Str } }
|
||||
local log = Manager.log:call("name=%q", name)
|
||||
|
||||
if self.project ~= nil and self.project.name == name then return log:ok() end
|
||||
|
||||
local projects = self:get_projects()
|
||||
local project = projects[name]
|
||||
if project == nil then return log:err "project doesn't exist" end
|
||||
|
||||
self:close_project()
|
||||
self.project = project
|
||||
|
||||
self.env:update(self.project)
|
||||
|
||||
project:open()
|
||||
|
||||
log:ok()
|
||||
end
|
||||
|
||||
function Manager:open_project_config()
|
||||
local log = Manager.log:call()
|
||||
|
||||
if self.project == nil then return log:ok() end
|
||||
|
||||
vim.cmd.edit(tostring(self.project.config_script))
|
||||
|
||||
log:ok()
|
||||
end
|
||||
|
||||
function Manager:close_project()
|
||||
local log = Manager.log:call()
|
||||
if self.project == nil then return log:ok() end
|
||||
|
||||
self.project:close()
|
||||
self.project = nil
|
||||
|
||||
self.env:update()
|
||||
|
||||
log:ok()
|
||||
end
|
||||
|
||||
return Manager
|
||||
238
lua/cave/meta.lua
Normal file
238
lua/cave/meta.lua
Normal file
@@ -0,0 +1,238 @@
|
||||
---@alias cave.Validator fun(v: any) : boolean
|
||||
|
||||
---@class cave.Meta
|
||||
---@field valid cave.Validator
|
||||
---@field repr string
|
||||
local Meta = {}
|
||||
Meta.__index = Meta
|
||||
|
||||
---@alias cave.MetaLikeItem string|table|cave.Meta
|
||||
---@alias cave.MetaLike cave.MetaLikeItem|cave.MetaLikeItem[]
|
||||
|
||||
---@param repr string
|
||||
---@param valid cave.Validator
|
||||
---@return cave.Meta
|
||||
function Meta.new(repr, valid)
|
||||
vim.validate {
|
||||
repr = { repr, "string" },
|
||||
valid = { valid, "function" },
|
||||
}
|
||||
local meta = setmetatable({}, Meta)
|
||||
meta.valid = valid
|
||||
meta.repr = repr
|
||||
return meta
|
||||
end
|
||||
|
||||
---@param ... cave.MetaLikeItem
|
||||
---@return cave.Meta
|
||||
function Meta.Union(...)
|
||||
local value_valids = {}
|
||||
local value_reprs = {}
|
||||
for idx, value_meta_like in ipairs { ... } do
|
||||
local value_meta = Meta.like(value_meta_like)
|
||||
value_valids[idx] = value_meta.valid
|
||||
value_reprs[idx] = value_meta.repr
|
||||
end
|
||||
local repr = ("Union<%s>"):format(table.concat(value_reprs, ","))
|
||||
local function valid(v)
|
||||
for _, value_valid in pairs(value_valids) do
|
||||
if value_valid(v) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
return Meta.new(repr, valid)
|
||||
end
|
||||
|
||||
---@param value_meta_like cave.MetaLike
|
||||
---@return cave.Meta
|
||||
function Meta.Optional(value_meta_like)
|
||||
local value_meta = Meta.like(value_meta_like)
|
||||
local repr = ("Optional<%s>"):format(value_meta.repr)
|
||||
local function valid(v) return v == nil or value_meta.valid(v) end
|
||||
return Meta.new(repr, valid)
|
||||
end
|
||||
|
||||
---@param mt table
|
||||
---@param name string
|
||||
---@param valid cave.Validator?
|
||||
---@return cave.Meta
|
||||
function Meta.Class(mt, name, valid)
|
||||
assert(type(mt) == "table")
|
||||
local repr = name
|
||||
---@param v any
|
||||
---@return boolean
|
||||
local function default_valid(v)
|
||||
if type(v) ~= "table" then return false end
|
||||
local v_mt = getmetatable(v)
|
||||
while v_mt ~= nil do
|
||||
if v_mt == mt then return true end
|
||||
v_mt = getmetatable(v_mt)
|
||||
end
|
||||
return false
|
||||
end
|
||||
valid = valid or default_valid
|
||||
return Meta.new(repr, valid)
|
||||
end
|
||||
|
||||
---@param tbl table<string,string>
|
||||
---@param name string
|
||||
---@return cave.Meta
|
||||
function Meta.Enum(tbl, name)
|
||||
assert(type(tbl) == "table")
|
||||
local repr = ("Enum<%s>(%s)"):format(name, table.concat(vim.tbl_values(tbl), "|"))
|
||||
local function valid(v) return type(v) == "string" and tbl[v] == v end
|
||||
return Meta.new(repr, valid)
|
||||
end
|
||||
|
||||
---@param value_meta_like cave.MetaLike
|
||||
---@return cave.Meta
|
||||
function Meta.List(value_meta_like)
|
||||
local value_meta = Meta.like(value_meta_like)
|
||||
local repr = ("List<%s>"):format(value_meta.repr)
|
||||
local function valid(vs)
|
||||
if not vim.tbl_islist(vs) then return false end
|
||||
for _, v in ipairs(vs) do
|
||||
if not value_meta.valid(v) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return Meta.new(repr, valid)
|
||||
end
|
||||
|
||||
---@param key_meta_like cave.MetaLike
|
||||
---@param value_meta_like cave.MetaLike
|
||||
---@return cave.Meta
|
||||
function Meta.Map(key_meta_like, value_meta_like)
|
||||
local key_meta = Meta.like(key_meta_like)
|
||||
local value_meta = Meta.like(value_meta_like)
|
||||
local repr = ("Map<%s,%s>"):format(key_meta.repr, value_meta.repr)
|
||||
local function valid(vs)
|
||||
if type(vs) ~= "table" then return false end
|
||||
for k, v in ipairs(vs) do
|
||||
if not key_meta.valid(k) or value_meta.valid(v) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return Meta.new(repr, valid)
|
||||
end
|
||||
|
||||
---@param meta_like_tbl table<string, cave.MetaLike>
|
||||
---@param name string
|
||||
---@return cave.Meta
|
||||
function Meta.MapLiteral(meta_like_tbl, name)
|
||||
---@type table<string, cave.Meta>
|
||||
local metas = {}
|
||||
for key, meta_like in meta_like_tbl do
|
||||
metas[key] = Meta.like(meta_like)
|
||||
end
|
||||
---@param vs any
|
||||
---@return boolean
|
||||
local function valid(vs)
|
||||
if type(vs) ~= "table" then return false end
|
||||
for key, meta in pairs(metas) do
|
||||
local value = vs[key]
|
||||
if not meta.valid(value) then return false end
|
||||
end
|
||||
for key, _ in pairs(vs) do
|
||||
if metas[key] == nil then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return Meta.new(name, valid)
|
||||
end
|
||||
|
||||
Meta.Bool = Meta.new("boolean", function(v) return type(v) == "boolean" end)
|
||||
Meta.Function = Meta.new("function", function(v) return type(v) == "function" end)
|
||||
Meta.Number = Meta.new("number", function(v) return type(v) == "number" end)
|
||||
Meta.String = Meta.new("string", function(v) return type(v) == "string" end)
|
||||
Meta.Table = Meta.new("table", function(v) return type(v) == "table" end)
|
||||
Meta.Nil = Meta.new("nil", function(v) return v == nil end)
|
||||
|
||||
local meta_aliases = {
|
||||
["b"] = Meta.Bool,
|
||||
["bool"] = Meta.Bool,
|
||||
["boolean"] = Meta.Bool,
|
||||
["f"] = Meta.Function,
|
||||
["fn"] = Meta.Function,
|
||||
["function"] = Meta.Function,
|
||||
["n"] = Meta.Number,
|
||||
["num"] = Meta.Number,
|
||||
["number"] = Meta.Number,
|
||||
["nil"] = Meta.Nil,
|
||||
["s"] = Meta.String,
|
||||
["str"] = Meta.String,
|
||||
["string"] = Meta.String,
|
||||
["t"] = Meta.Table,
|
||||
["tbl"] = Meta.Table,
|
||||
["table"] = Meta.Table,
|
||||
}
|
||||
|
||||
---@param meta_like cave.MetaLike
|
||||
---@return cave.Meta
|
||||
function Meta.like(meta_like)
|
||||
local meta_like_type = type(meta_like)
|
||||
local meta
|
||||
if meta_like_type == "string" then
|
||||
meta = meta_aliases[meta_like]
|
||||
else
|
||||
assert(meta_like_type == "table")
|
||||
local mt = getmetatable(meta_like)
|
||||
if mt == Meta then
|
||||
meta = meta_like
|
||||
elseif meta_like.__meta ~= nil then
|
||||
meta = meta_like.__meta
|
||||
elseif vim.tbl_islist(meta_like) then
|
||||
meta = Meta.Union(unpack(meta_like))
|
||||
else
|
||||
assert(false)
|
||||
end
|
||||
end
|
||||
assert(getmetatable(meta) == Meta)
|
||||
return meta
|
||||
end
|
||||
|
||||
---@return cave.Validator
|
||||
---@return string
|
||||
function Meta:check() return self.valid, self.repr end
|
||||
|
||||
---@param params table<string,table>
|
||||
function Meta.validate(params)
|
||||
local vim_params = {}
|
||||
for param_name, param_specs in pairs(params) do
|
||||
assert(type(param_name) == "string", "param name is not a string")
|
||||
assert(type(param_specs) == "table", "param spec for '" .. param_name .. "' is not a table")
|
||||
assert(#param_specs == 2, "param spec length for '" .. param_name .. "' is not 2")
|
||||
local param_value = param_specs[1] --[[@as any]]
|
||||
local param_meta_like = param_specs[2] --[[@as cave.MetaLike]]
|
||||
local param_meta = Meta.like(param_meta_like)
|
||||
vim_params[param_name] = { param_value, param_meta:check() }
|
||||
end
|
||||
vim.validate(vim_params)
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param base_mt table?
|
||||
---@return table
|
||||
function Meta.derive(name, base_mt)
|
||||
Meta.validate { name = { name, Meta.String }, base_mt = { base_mt, Meta.Optional(Meta.Table) } }
|
||||
local mt = {}
|
||||
mt.__index = mt
|
||||
mt.__meta = Meta.Class(mt, name)
|
||||
return (base_mt and setmetatable(mt, base_mt)) or mt
|
||||
end
|
||||
|
||||
---@param obj table
|
||||
---@return string
|
||||
function Meta.get_repr(obj)
|
||||
Meta.validate { obj = { obj, Meta.Table } }
|
||||
local mt = getmetatable(obj)
|
||||
Meta.validate { mt = { mt, Meta.Table } }
|
||||
local meta = mt.__meta
|
||||
Meta.validate { meta = { meta, Meta.Table } }
|
||||
local meta_mt = getmetatable(obj)
|
||||
assert(meta_mt == Meta)
|
||||
---@cast meta cave.Meta
|
||||
return meta.repr
|
||||
end
|
||||
|
||||
return Meta
|
||||
13
lua/cave/option.lua
Normal file
13
lua/cave/option.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
---@class cave.Option
|
||||
local Option
|
||||
|
||||
---@generic ValueType, ResultType
|
||||
---@param opt ValueType?
|
||||
---@param fn fun(opt: ValueType): ResultType
|
||||
---@return ResultType?
|
||||
function Option.map(opt, fn)
|
||||
if opt == nil then return nil end
|
||||
return fn(opt)
|
||||
end
|
||||
|
||||
return Option
|
||||
92
lua/cave/path.lua
Normal file
92
lua/cave/path.lua
Normal file
@@ -0,0 +1,92 @@
|
||||
local Meta = require "cave.meta"
|
||||
|
||||
local PosixPath = require "pathlib.posix" --[[@as PathlibPosixPath]]
|
||||
|
||||
local List = Meta.List
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
|
||||
---@alias cave.PathLikeItem string|cave.Path
|
||||
---@alias cave.PathLike cave.PathLikeItem|cave.PathLikeItem[]
|
||||
|
||||
---@class cave.Path : PathlibPosixPath
|
||||
---@operator div(cave.PathLikeItem): cave.Path
|
||||
---@operator concat(cave.PathLikeItem): string
|
||||
local Path = Meta.derive("Path", PosixPath)
|
||||
require("pathlib.utils.paths").link_dunders(Path, PosixPath)
|
||||
|
||||
Path.LikeItem = { Str, Path }
|
||||
Path.LikeItemList = List { Str, Path }
|
||||
Path.Like = { Str, Path, Path.LikeItemList }
|
||||
|
||||
---@param path_like cave.PathLike
|
||||
---@return cave.Path
|
||||
function Path.like(path_like)
|
||||
validate { path_like = { path_like, Path.Like } }
|
||||
local self = Path.new_empty()
|
||||
local path_like_type = type(path_like)
|
||||
if path_like_type == "string" or not vim.tbl_islist(path_like) then
|
||||
self:_init(path_like)
|
||||
else
|
||||
self:_init(unpack(path_like))
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
---@param path cave.Path
|
||||
---@return cave.Path
|
||||
function Path:copy_all_from(path)
|
||||
---@type cave.Path
|
||||
return PosixPath.copy_all_from(self, path)
|
||||
end
|
||||
|
||||
---@return cave.Path
|
||||
function Path:copy() return Path.new_empty():copy_all_from(self) end
|
||||
|
||||
---@param ... cave.PathLikeItem
|
||||
---@return cave.Path
|
||||
function Path.new(...)
|
||||
validate { ["..."] = { { ... }, Path.LikeItemList } }
|
||||
local self = Path.new_empty()
|
||||
self:_init(...)
|
||||
return self
|
||||
end
|
||||
|
||||
---@return cave.Path
|
||||
function Path.new_empty()
|
||||
local self = setmetatable({}, Path)
|
||||
self:to_empty()
|
||||
return self
|
||||
end
|
||||
|
||||
---@return cave.Path
|
||||
function Path.cwd() return Path.new(vim.fn.getcwd()) end
|
||||
|
||||
---@return cave.Path
|
||||
function Path.home() return Path.new(vim.loop.os_homedir()) end
|
||||
|
||||
---@param what string
|
||||
---@param ... cave.PathLikeItem
|
||||
---@return cave.Path
|
||||
function Path.stdpath(what, ...)
|
||||
validate { what = { what, Str }, ["..."] = { { ... }, Path.LikeItemList } }
|
||||
return Path.new(vim.fn.stdpath(what), ...)
|
||||
end
|
||||
|
||||
-- ---@return cave.Path
|
||||
-- function Path:to_absolute(cwd) return PosixPath.to_absolute(self, cwd) end
|
||||
|
||||
---@param name cave.PathLikeItem
|
||||
---@return cave.Path
|
||||
function Path.executable(name)
|
||||
validate { name = { name, { Str, Path } } }
|
||||
if type(name) ~= "string" then name = tostring(name) end
|
||||
local s = vim.fn.exepath(name)
|
||||
assert(#s > 0, ("'%s' is not executable"):format(name))
|
||||
return Path.new(s)
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function Path:is_executable() return vim.fn.executable(self:tostring()) == 1 end
|
||||
|
||||
return Path
|
||||
235
lua/cave/project.lua
Normal file
235
lua/cave/project.lua
Normal file
@@ -0,0 +1,235 @@
|
||||
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
|
||||
9
lua/cave/python/init.lua
Normal file
9
lua/cave/python/init.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
---@class cave.Python
|
||||
local Python = {
|
||||
Interpreter = require "cave.python.interpreter",
|
||||
Module = require "cave.python.module",
|
||||
Runnable = require "cave.python.runnable",
|
||||
Script = require "cave.python.script",
|
||||
}
|
||||
|
||||
return Python
|
||||
236
lua/cave/python/interpreter.lua
Normal file
236
lua/cave/python/interpreter.lua
Normal file
@@ -0,0 +1,236 @@
|
||||
local Context = require "cave.context"
|
||||
local Meta = require "cave.meta"
|
||||
local Module = require "cave.python.module"
|
||||
local Path = require "cave.path"
|
||||
local Runnable = require "cave.python.runnable"
|
||||
local Script = require "cave.python.script"
|
||||
local Task = require "cave.task"
|
||||
|
||||
local List = Meta.List
|
||||
local Map = Meta.Map
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
|
||||
---@class cave.Python.Interpreter
|
||||
---@field id string
|
||||
---@field path cave.Path
|
||||
---@field args string[]
|
||||
---@field env table<string, string>
|
||||
---@field runnables table<string, cave.Python.Runnable>
|
||||
---@field context cave.Context
|
||||
local Interpreter = Meta.derive "Python.Interpreter"
|
||||
|
||||
---@return string
|
||||
function Interpreter:valid_path() return self.path:executable():tostring() end
|
||||
|
||||
---@return overseer.TemplateDefinition[]
|
||||
function Interpreter:templates()
|
||||
local templates = {}
|
||||
for _, runnable in pairs(self.runnables) do
|
||||
vim.list_extend(templates, { self:run_template(runnable), self:debug_template(runnable) })
|
||||
end
|
||||
return templates
|
||||
end
|
||||
|
||||
---@param runnable cave.Python.Runnable
|
||||
---@return overseer.TemplateDefinition
|
||||
function Interpreter:run_template(runnable)
|
||||
local name = ("python.%s.run.%s"):format(self.id, runnable.id)
|
||||
local script, module = runnable:concrete()
|
||||
local args = vim.list_extend({}, self.args)
|
||||
vim.list_extend(
|
||||
args,
|
||||
(script and { script:valid_file() }) or (module and { "-m", module.name }) or error "Unsupported runnable"
|
||||
)
|
||||
vim.list_extend(args, runnable.args)
|
||||
local template_definition = {
|
||||
name = name,
|
||||
builder = function()
|
||||
---@type overseer.TaskDefinition
|
||||
local task_definition = {
|
||||
name = name,
|
||||
cmd = { self:valid_path() },
|
||||
args = args,
|
||||
env = vim.tbl_extend("keep", runnable.env, self.env),
|
||||
cwd = runnable:valid_cwd(),
|
||||
components = { { "defaults" } },
|
||||
}
|
||||
return task_definition
|
||||
end,
|
||||
params = {},
|
||||
tags = { Task.Tag.Run },
|
||||
}
|
||||
return template_definition
|
||||
end
|
||||
|
||||
---@param runnable cave.Python.Runnable
|
||||
---@return overseer.TemplateDefinition
|
||||
function Interpreter:debug_template(runnable)
|
||||
local name = ("python.%s.debug.%s"):format(self.id, runnable.id)
|
||||
local template_definition = {}
|
||||
template_definition.builder = function()
|
||||
local script, module = runnable:concrete()
|
||||
|
||||
---@type DebugpyLaunchConfig
|
||||
local dap_config = {
|
||||
name = name,
|
||||
type = "python",
|
||||
request = "launch",
|
||||
module = module and module.name,
|
||||
program = script and script:valid_file(),
|
||||
cwd = runnable:valid_cwd(),
|
||||
args = runnable.args,
|
||||
env = vim.tbl_extend("keep", runnable.env, self.env),
|
||||
python = vim.list_extend({ self:valid_path() }, self.args),
|
||||
}
|
||||
|
||||
if vim.tbl_isempty(dap_config.env) then dap_config.env = nil end
|
||||
|
||||
---@type overseer.TaskDefinition
|
||||
local task_definition = {
|
||||
name = name,
|
||||
cmd = {},
|
||||
components = { { "defaults" }, { "dap", config = dap_config } },
|
||||
}
|
||||
return task_definition
|
||||
end
|
||||
template_definition.params = {}
|
||||
template_definition.tags = { Task.Tag.Debug }
|
||||
template_definition.name = name
|
||||
return template_definition
|
||||
end
|
||||
|
||||
---@class cave.Python.Interpreter.Factory
|
||||
---@field id_ string?
|
||||
---@field path_ cave.Path?
|
||||
---@field args_ string[]
|
||||
---@field env_ table<string, string>
|
||||
---@field runnables_ cave.Python.Runnable.Factory[]
|
||||
---@field context_ cave.Context
|
||||
local Factory = Meta.derive "Python.Interpreter.Factory"
|
||||
|
||||
---@param context cave.Context
|
||||
function Factory:init(context)
|
||||
self.args_ = {}
|
||||
self.env_ = {}
|
||||
self.runnables_ = {}
|
||||
self.context_ = context
|
||||
end
|
||||
|
||||
---@param context cave.Context
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory.new(context)
|
||||
validate { context = { context, Context } }
|
||||
local factory = setmetatable({}, Factory)
|
||||
factory:init(context)
|
||||
return factory
|
||||
end
|
||||
|
||||
---@return string
|
||||
function Factory:get_id() return self.id_ or "python" end
|
||||
|
||||
---@return cave.Path
|
||||
function Factory:get_path() return self.path_ or Path.new "python" end
|
||||
|
||||
---@return string[]
|
||||
function Factory:get_args() return self.args_ end
|
||||
|
||||
---@return table<string, string>
|
||||
function Factory:get_env() return self.env_ end
|
||||
|
||||
---@return cave.Python.Runnable.Factory[]
|
||||
function Factory:get_runnables() return self.runnables_ end
|
||||
|
||||
---@param id string
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:id(id)
|
||||
validate { id = { id, Str } }
|
||||
self.id_ = id
|
||||
return self
|
||||
end
|
||||
|
||||
---@param path_like cave.PathLike
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:path(path_like)
|
||||
validate { path_like = { path_like, Path.Like } }
|
||||
self.path_ = Path.like(path_like)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:args(args)
|
||||
validate { args = { args, List(Str) } }
|
||||
vim.list_extend(self.args_, args)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param arg string
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:arg(arg) return self:args { arg } end
|
||||
|
||||
---@param env table<string, string>
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:env(env)
|
||||
validate { env = { env, Map(Str, Str) } }
|
||||
vim.tbl_extend("error", self.env_, env)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@return cave.Python.Module.Factory
|
||||
function Factory:module(name)
|
||||
validate { name = { name, Str } }
|
||||
local module_factory = Module.Factory.new(name, self.context_)
|
||||
table.insert(self.runnables_, module_factory)
|
||||
return module_factory
|
||||
end
|
||||
|
||||
---@param file_path_like cave.PathLike
|
||||
---@return cave.Python.Script.Factory
|
||||
function Factory:script(file_path_like)
|
||||
validate { file = { file_path_like, Path.Like } }
|
||||
local file = Path.like(file_path_like)
|
||||
local script_factory = Script.Factory.new(file, self.context_)
|
||||
table.insert(self.runnables_, script_factory)
|
||||
return script_factory
|
||||
end
|
||||
|
||||
---@param runnables cave.Python.Runnable.Factory[]
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:runnables(runnables)
|
||||
validate { runnables = { runnables, List(Runnable.Factory) } }
|
||||
for _, runnable in ipairs(runnables) do
|
||||
table.insert(self.runnables_, runnable:copy())
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
---@param runnable cave.Python.Runnable.Factory
|
||||
---@return cave.Python.Interpreter.Factory
|
||||
function Factory:runnable(runnable) return self:runnables { runnable } end
|
||||
|
||||
---@param interpreter cave.Python.Interpreter
|
||||
function Factory:init_interpreter(interpreter)
|
||||
interpreter.id = self:get_id()
|
||||
interpreter.path = self:get_path()
|
||||
interpreter.args = self:get_args()
|
||||
interpreter.env = self:get_env()
|
||||
interpreter.runnables = {}
|
||||
for _, runnable_factory in pairs(self:get_runnables()) do
|
||||
local runnable = runnable_factory:build()
|
||||
assert(interpreter.runnables[runnable.id] == nil)
|
||||
interpreter.runnables[runnable.id] = runnable
|
||||
end
|
||||
end
|
||||
|
||||
---@return cave.Python.Interpreter
|
||||
function Factory:build()
|
||||
local interpreter = setmetatable({}, Interpreter)
|
||||
self:init_interpreter(interpreter)
|
||||
return interpreter
|
||||
end
|
||||
|
||||
Interpreter.Factory = Factory
|
||||
|
||||
return Interpreter
|
||||
69
lua/cave/python/module.lua
Normal file
69
lua/cave/python/module.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
local Runnable = require "cave.python.runnable"
|
||||
local Context = require "cave.context"
|
||||
local Meta = require "cave.meta"
|
||||
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
|
||||
---@class cave.Python.Module : cave.Python.Runnable
|
||||
---@field name string
|
||||
local Module = Meta.derive("Python.Module", Runnable)
|
||||
|
||||
function Module:module() return self end
|
||||
|
||||
---@class cave.Python.Module.Factory : cave.Python.Runnable.Factory
|
||||
---@field name_ string
|
||||
local Factory = Meta.derive("Python.Module.Factory", Runnable.Factory)
|
||||
|
||||
---@param name string
|
||||
---@param context cave.Context
|
||||
function Factory:init(name, context)
|
||||
Runnable.Factory.init(self, context)
|
||||
self.name_ = name
|
||||
end
|
||||
|
||||
---@param other cave.Python.Module.Factory
|
||||
function Factory:copy_from(other)
|
||||
Runnable.Factory.copy_from(self, other)
|
||||
self.name_ = other.name_
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@param context cave.Context
|
||||
---@return cave.Python.Module.Factory
|
||||
function Factory.new(name, context)
|
||||
validate { name = { name, Str }, context = { context, Context } }
|
||||
local factory = setmetatable({}, Factory)
|
||||
factory:init(name, context)
|
||||
return factory
|
||||
end
|
||||
|
||||
---@return cave.Python.Module.Factory
|
||||
function Factory:copy()
|
||||
local factory = setmetatable({}, Factory)
|
||||
factory:copy_from(self)
|
||||
return factory
|
||||
end
|
||||
|
||||
---@return string
|
||||
function Factory:get_id() return self.id_ or self:get_name() end
|
||||
|
||||
---@return string
|
||||
function Factory:get_name() return self.name_ end
|
||||
|
||||
---@param module cave.Python.Module
|
||||
function Factory:init_module(module)
|
||||
self:init_runnable(module)
|
||||
module.name = self:get_name()
|
||||
end
|
||||
|
||||
---@return cave.Python.Module
|
||||
function Factory:build()
|
||||
local module = setmetatable({}, Module)
|
||||
self:init_module(module)
|
||||
return module
|
||||
end
|
||||
|
||||
Module.Factory = Factory
|
||||
|
||||
return Module
|
||||
31
lua/cave/python/runnable.lua
Normal file
31
lua/cave/python/runnable.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
local Meta = require "cave.meta"
|
||||
local Task = require "cave.task"
|
||||
|
||||
---@class cave.Python.Runnable : cave.Task
|
||||
local Runnable = Meta.derive("Python.Runnable", Task)
|
||||
|
||||
---@return cave.Python.Script?
|
||||
---@return cave.Python.Module?
|
||||
function Runnable:concrete() return self:script(), self:module() end
|
||||
|
||||
---@return cave.Python.Script?
|
||||
function Runnable:script() end
|
||||
|
||||
---@return cave.Python.Module?
|
||||
function Runnable:module() end
|
||||
|
||||
---@class cave.Python.Runnable.Factory : cave.Task.Factory
|
||||
local Factory = Meta.derive("Python.Runnable.Factory", Task.Factory)
|
||||
|
||||
---@return cave.Python.Runnable
|
||||
function Factory:build() error "Not implemented" end
|
||||
|
||||
---@return cave.Python.Runnable
|
||||
function Factory:copy() error "Not implemented" end
|
||||
|
||||
---@param runnable cave.Python.Runnable
|
||||
function Factory:init_runnable(runnable) self:init_task(runnable) end
|
||||
|
||||
Runnable.Factory = Factory
|
||||
|
||||
return Runnable
|
||||
76
lua/cave/python/script.lua
Normal file
76
lua/cave/python/script.lua
Normal file
@@ -0,0 +1,76 @@
|
||||
local Runnable = require "cave.python.runnable"
|
||||
local Meta = require "cave.meta"
|
||||
local Path = require "cave.path"
|
||||
local Context = require "cave.context"
|
||||
|
||||
local validate = Meta.validate
|
||||
|
||||
---@class cave.Python.Script : cave.Python.Runnable
|
||||
---@field file cave.Path
|
||||
local Script = Meta.derive("Python.Script", Runnable)
|
||||
|
||||
---@return cave.Python.Script
|
||||
function Script:script() return self end
|
||||
|
||||
---@return string
|
||||
function Script:valid_file()
|
||||
assert(self.file:is_file())
|
||||
return self.file:tostring()
|
||||
end
|
||||
|
||||
---@class cave.Python.Script.Factory : cave.Python.Runnable.Factory
|
||||
---@field file_ cave.Path
|
||||
local Factory = Meta.derive("Python.Script.Factory", Runnable.Factory)
|
||||
|
||||
---@param file cave.Path
|
||||
---@param context cave.Context
|
||||
function Factory:init(file, context)
|
||||
Runnable.Factory.init(self, context)
|
||||
self.file_ = file
|
||||
end
|
||||
|
||||
---@param other cave.Python.Script.Factory
|
||||
function Factory:copy_from(other)
|
||||
Runnable.Factory.copy_from(self, other)
|
||||
self.file_ = other.file_:copy()
|
||||
end
|
||||
|
||||
---@param file cave.Path
|
||||
---@param context cave.Context
|
||||
---@return cave.Python.Script.Factory
|
||||
function Factory.new(file, context)
|
||||
validate { file = { file, Path }, context = { context, Context } }
|
||||
local factory = setmetatable({}, Factory)
|
||||
factory:init(file, context)
|
||||
return factory
|
||||
end
|
||||
|
||||
---@return cave.Python.Script.Factory
|
||||
function Factory:copy()
|
||||
local factory = setmetatable({}, Factory)
|
||||
factory:copy_from(self)
|
||||
return factory
|
||||
end
|
||||
|
||||
---@return string
|
||||
function Factory:get_id() return self.id_ or ("[%s]"):format(self:get_file()) end
|
||||
|
||||
---@return cave.Path
|
||||
function Factory:get_file() return self.file_ end
|
||||
|
||||
---@param script cave.Python.Script
|
||||
function Factory:init_script(script)
|
||||
self:init_runnable(script)
|
||||
script.file = self:get_file()
|
||||
end
|
||||
|
||||
---@return cave.Python.Script
|
||||
function Factory:build()
|
||||
local script = setmetatable({}, Script)
|
||||
self:init_script(script)
|
||||
return script
|
||||
end
|
||||
|
||||
Script.Factory = Factory
|
||||
|
||||
return Script
|
||||
124
lua/cave/task.lua
Normal file
124
lua/cave/task.lua
Normal file
@@ -0,0 +1,124 @@
|
||||
local Path = require "cave.path"
|
||||
local Meta = require "cave.meta"
|
||||
local Enum = require "cave.enum"
|
||||
|
||||
local List = Meta.List
|
||||
local Map = Meta.Map
|
||||
local Optional = Meta.Optional
|
||||
local Str = Meta.String
|
||||
local validate = Meta.validate
|
||||
|
||||
---@enum cave.Task.Tag
|
||||
local Tag = {
|
||||
Run = "Run",
|
||||
Debug = "Debug",
|
||||
}
|
||||
Enum.new(Tag, "Task.Tag")
|
||||
|
||||
---@class cave.Task
|
||||
---@field id string
|
||||
---@field args string[]
|
||||
---@field cwd cave.Path
|
||||
---@field env table<string, string>
|
||||
local Task = Meta.derive "Task"
|
||||
|
||||
Task.Tag = Tag
|
||||
|
||||
---@return string
|
||||
function Task:valid_cwd()
|
||||
assert(self.cwd:is_dir())
|
||||
return self.cwd:tostring()
|
||||
end
|
||||
|
||||
---@class cave.Task.Factory
|
||||
---@field id_ string?
|
||||
---@field args_ string[]
|
||||
---@field cwd_ cave.Path?
|
||||
---@field env_ table<string, string>
|
||||
---@field context_ cave.Context
|
||||
local Factory = Meta.derive "Task.Factory"
|
||||
|
||||
---@param context cave.Context
|
||||
function Factory:init(context)
|
||||
self.args_ = {}
|
||||
self.env_ = {}
|
||||
self.context_ = context
|
||||
end
|
||||
|
||||
---@param other cave.Task.Factory
|
||||
function Factory:copy_from(other)
|
||||
self.id_ = other.id_
|
||||
self.args_ = vim.deepcopy(other.args_)
|
||||
self.cwd_ = other.cwd_ and other.cwd_:copy()
|
||||
self.env_ = vim.deepcopy(other.env_)
|
||||
self.context_ = other.context_
|
||||
end
|
||||
|
||||
---@return string
|
||||
function Factory:get_id()
|
||||
assert(self.id_)
|
||||
return self.id_
|
||||
end
|
||||
|
||||
---@return string[]
|
||||
function Factory:get_args() return self.args_ end
|
||||
|
||||
---@return cave.Path
|
||||
function Factory:get_cwd() return self.cwd_ or Path.new(self.context_.dir) end
|
||||
|
||||
---@return table<string, string>
|
||||
function Factory:get_env() return self.env_ end
|
||||
|
||||
---@param id string
|
||||
---@return cave.Task.Factory
|
||||
function Factory:id(id)
|
||||
validate { id = { id, Str } }
|
||||
self.id_ = id
|
||||
return self
|
||||
end
|
||||
|
||||
---@param args string[]
|
||||
---@return cave.Task.Factory
|
||||
function Factory:args(args)
|
||||
validate { args = { args, List(Str) } }
|
||||
vim.list_extend(self.args_, args)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param arg string
|
||||
---@return cave.Task.Factory
|
||||
function Factory:arg(arg) return self:args { arg } end
|
||||
|
||||
---@param cwd_path_like cave.PathLike
|
||||
---@return cave.Task.Factory
|
||||
function Factory:cwd(cwd_path_like)
|
||||
validate { cwd_path_like = { cwd_path_like, Optional(Path.Like) } }
|
||||
self.cwd_ = Path.like(cwd_path_like)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param env table<string, string>
|
||||
---@return cave.Task.Factory
|
||||
function Factory:env(env)
|
||||
validate { env = { env, Map(Str, Str) } }
|
||||
vim.tbl_extend("error", self.env_, env)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param task cave.Task
|
||||
function Factory:init_task(task)
|
||||
task.id = self:get_id()
|
||||
task.args = self:get_args()
|
||||
task.cwd = self:get_cwd()
|
||||
task.env = self:get_env()
|
||||
end
|
||||
|
||||
---@return cave.Task
|
||||
function Factory:build() error "Not implemented" end
|
||||
|
||||
---@return cave.Task
|
||||
function Factory:copy() error "Not implemented" end
|
||||
|
||||
Task.Factory = Factory
|
||||
|
||||
return Task
|
||||
0
lua/cave/template.lua
Normal file
0
lua/cave/template.lua
Normal file
23
lua/cave/template_provider.lua
Normal file
23
lua/cave/template_provider.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local Meta = require "cave.meta"
|
||||
local ClassLogger = require "cave.log.class_logger"
|
||||
|
||||
---@class cave.TemplateProvider : overseer.TemplateProvider
|
||||
---@field get_templates fun(): overseer.TemplateDefinition[]
|
||||
local TemplateProvider = Meta.derive "TemplateProvider"
|
||||
TemplateProvider.log = ClassLogger.new(TemplateProvider)
|
||||
|
||||
function TemplateProvider:init(name, get_templates_fn)
|
||||
self.name = name
|
||||
self.get_templates = get_templates_fn
|
||||
---@type fun(opts: overseer.SearchParams, cb: fun(tmpls: overseer.TemplateDefinition[]))
|
||||
self.generator = function(_, cb) cb(self.get_templates()) end
|
||||
end
|
||||
|
||||
---@return cave.TemplateProvider
|
||||
function TemplateProvider.new(name, get_templates_fn)
|
||||
local provider = setmetatable({}, TemplateProvider)
|
||||
provider:init(name, get_templates_fn)
|
||||
return provider
|
||||
end
|
||||
|
||||
return TemplateProvider
|
||||
84
lua/cave/util.lua
Normal file
84
lua/cave/util.lua
Normal file
@@ -0,0 +1,84 @@
|
||||
local Path = require "cave.path"
|
||||
local Meta = require "cave.meta"
|
||||
|
||||
local buffers = require "astrocore.buffer"
|
||||
|
||||
local Table = Meta.Table
|
||||
local validate = Meta.validate
|
||||
local List = Meta.List
|
||||
local Str = Meta.String
|
||||
|
||||
local Util = {}
|
||||
|
||||
---@param old table
|
||||
---@param new table
|
||||
---@return table
|
||||
function Util.tbl_diff(old, new)
|
||||
validate { old = { old, Table }, new = { new, Table } }
|
||||
local diff = {
|
||||
added = {},
|
||||
removed = {},
|
||||
modified = {},
|
||||
}
|
||||
for old_name, old_value in pairs(old) do
|
||||
local new_value = new[old_name]
|
||||
if new_value == nil then
|
||||
diff.removed[old_name] = old_value
|
||||
elseif type(old_value) ~= type(new_value) or old_value ~= new_value then
|
||||
diff.modified[old_name] = { old = old_value, new = new_value }
|
||||
end
|
||||
end
|
||||
|
||||
for new_name, new_value in pairs(new) do
|
||||
local old_value = old[new_name]
|
||||
if old_value == nil then
|
||||
diff.added[new_name] = new_value
|
||||
elseif type(old_value) ~= type(new_value) or old_value ~= new_value then
|
||||
assert(diff.modified[new_name].old == old_value and diff.modified[new_name].new == new_value)
|
||||
end
|
||||
end
|
||||
return diff
|
||||
end
|
||||
|
||||
function Util.save_all_buffers()
|
||||
for _, buf in ipairs(vim.t.bufs) do
|
||||
local buf_valid = buffers.is_valid(buf)
|
||||
local buf_modified = vim.api.nvim_buf_get_option(buf, "modified")
|
||||
if not buf_valid or not buf_modified then goto continue end
|
||||
local buf_name = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), "%")
|
||||
if buf_name == "" then goto continue end
|
||||
local confirm = vim.fn.confirm(('Save changes to "%s"?'):format(buf_name), "&Yes\n&No", 1, "Question")
|
||||
if confirm == 1 then vim.api.nvim_buf_call(buf, vim.cmd.write) end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
function Util.close_all_buffers() buffers.close_all() end
|
||||
|
||||
---@return string
|
||||
function Util.generate_uuid()
|
||||
local uuidgen_path = Path.new "uuidgen"
|
||||
assert(uuidgen_path:is_executable())
|
||||
local cmd = { tostring(uuidgen_path), "-t" }
|
||||
local output = vim.fn.systemlist(cmd)
|
||||
validate { output = { output, List(Str) } }
|
||||
assert(#output == 1)
|
||||
return output[1]
|
||||
end
|
||||
|
||||
---@param t any
|
||||
---@return any
|
||||
function Util.plain(t)
|
||||
if type(t) ~= "table" then return t end
|
||||
local mt = getmetatable(t)
|
||||
if mt ~= nil and (rawget(mt, "__tostring") ~= nil or rawget(mt, "__name") ~= nil) then
|
||||
return tostring(t)
|
||||
end
|
||||
setmetatable(t, nil)
|
||||
for key, value in pairs(t) do
|
||||
t[key] = Util.plain(value)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
return Util
|
||||
30
lua/overseer/component/dap.lua
Normal file
30
lua/overseer/component/dap.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
---@type overseer.ComponentFileDefinition
|
||||
return {
|
||||
desc = "DAP",
|
||||
constructor = function(params)
|
||||
---@type Configuration
|
||||
local config = params.config
|
||||
---@type overseer.ComponentSkeleton
|
||||
return {
|
||||
on_init = function(_, task)
|
||||
task.cmd = { vim.fn.exepath "true" }
|
||||
task:remove_component "on_complete_notify"
|
||||
task:add_component "on_complete_dispose"
|
||||
local ToggleTermStrategy = require "overseer.strategy.toggleterm"
|
||||
task.strategy = ToggleTermStrategy.new {
|
||||
auto_scroll = false,
|
||||
close_on_exit = false,
|
||||
quit_on_exit = "never",
|
||||
hidden = true,
|
||||
use_shell = false,
|
||||
open_on_start = false,
|
||||
}
|
||||
end,
|
||||
on_start = function()
|
||||
local dap = require "dap"
|
||||
dap.run(config, { new = true })
|
||||
end,
|
||||
}
|
||||
end,
|
||||
params = { config = { type = "opaque" } },
|
||||
}
|
||||
BIN
mod/__pycache__/spawner.cpython-312.pyc
Normal file
BIN
mod/__pycache__/spawner.cpython-312.pyc
Normal file
Binary file not shown.
0
mod/spawner.py
Normal file
0
mod/spawner.py
Normal file
Reference in New Issue
Block a user