diff --git a/doc/rocks.txt b/doc/rocks.txt index 1644c1d0..3029ca09 100644 --- a/doc/rocks.txt +++ b/doc/rocks.txt @@ -5,6 +5,7 @@ rocks.nvim ·································· rocks.nvim commands ··········································· |rocks.commands| rocks.nvim configuration ········································ |rocks.config| rocks.nvim Lua API ················································· |rocks.api| +rocks.nvim logging API ············································· |rocks.log| ============================================================================== rocks.nvim *rocks* @@ -62,19 +63,19 @@ The Lua API for rocks.nvim. Intended for use by modules that extend this plugin. -Rock *Rock* - - Fields: ~ - {name} (string) - {version} (string) - - rock_name *rock_name* Type: ~ string +Rock *Rock* + + Fields: ~ + {name} (rock_name) + {version} (string) + + api.try_get_cached_rocks() *api.try_get_cached_rocks* Tries to get the cached rocks. Returns an empty list if the cache has not been populated @@ -154,4 +155,55 @@ api.register_rocks_subcommand({name}, {cmd}) {cmd} (RocksCmd) +RockSpec *RockSpec* + + + { name: rock_name, version?: string, [string]: V } + +Specification for a rock in rocks.toml. + +rock_handler_callback *rock_handler_callback* + + Type: ~ + fun(report_progress:fun(message:string),report_error:fun(message:string)) + + +A function that operates on the rock, syncing it with the entry in rocks.toml + +RockHandler *RockHandler* + + Fields: ~ + {get_sync_callback} (fun(spec:RockSpec):rock_handler_callback|nil) Return a function that installs or updates the rock, or `nil` if the handler cannot or does not need to sync the rock. + {get_prune_callback} (fun(specs:table):rock_handler_callback|nil) Return a function that prunes unused rocks, or `nil` if the handler cannot or does not need to prune any rocks. + + +api.register_rock_handler({handler}) *api.register_rock_handler* + + Parameters: ~ + {handler} (RockHandler) + + +============================================================================== +rocks.nvim logging API *rocks.log* + + +The logging interface for rocks.nvim. +Intended to be used by external modules. + + +log.trace() *log.trace* + + +log.debug() *log.debug* + + +log.info() *log.info* + + +log.warn() *log.warn* + + +log.error() *log.error* + + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/lua/rocks/api.lua b/lua/rocks/api.lua index 7e633c79..f36695a7 100644 --- a/lua/rocks/api.lua +++ b/lua/rocks/api.lua @@ -16,12 +16,12 @@ -- Homepage: https://github.com/nvim-neorocks/rocks.nvim -- Maintainer: NTBBloodbath +---@alias rock_name string + ---@class Rock ----@field name string +---@field name rock_name ---@field version string ----@alias rock_name string - local api = {} local cache = require("rocks.cache") @@ -33,6 +33,7 @@ local fzy = require("rocks.fzy") local luarocks = require("rocks.luarocks") local nio = require("nio") local state = require("rocks.state") +local operations = require("rocks.operations") ---Tries to get the cached rocks. ---Returns an empty list if the cache has not been populated @@ -117,4 +118,25 @@ function api.register_rocks_subcommand(name, cmd) commands.register_subcommand(name, cmd) end +---@class RockSpec: { name: rock_name, version?: string, [string]: any } +---@brief [[ +--- { name: rock_name, version?: string, [string]: V } +--- +---Specification for a rock in rocks.toml. +---@brief ]] + +---@alias rock_handler_callback fun(report_progress: fun(message: string), report_error: fun(message: string)) +---@brief [[ +---A function that operates on the rock, syncing it with the entry in rocks.toml +---@brief ]] + +---@class RockHandler +---@field get_sync_callback fun(spec: RockSpec):rock_handler_callback|nil Return a function that installs or updates the rock, or `nil` if the handler cannot or does not need to sync the rock. +---@field get_prune_callback fun(specs: table):rock_handler_callback|nil Return a function that prunes unused rocks, or `nil` if the handler cannot or does not need to prune any rocks. + +---@param handler RockHandler +function api.register_rock_handler(handler) + operations.register_handler(handler) +end + return api diff --git a/lua/rocks/log.lua b/lua/rocks/log.lua index 32df9b3f..cbdcbcb6 100644 --- a/lua/rocks/log.lua +++ b/lua/rocks/log.lua @@ -1,8 +1,9 @@ ----@mod rocks.log rocks.nvim logging +---@mod rocks.log rocks.nvim logging API --- ---@brief [[ --- ----The internal logging interface for rocks.nvim +---The logging interface for rocks.nvim. +---Intended to be used by external modules. --- ---@brief ]] @@ -15,15 +16,21 @@ -- Homepage: https://github.com/nvim-neorocks/rocks.nvim -- Maintainer: NTBBloodbath -local log = { - -- NOTE: These functions are initialised as empty for type checking purposes - -- and implemented later. - trace = function(_) end, - debug = function(_) end, - info = function(_) end, - warn = function(_) end, - error = function(_) end, -} +local log = {} + +-- NOTE: These functions are initialised as empty for type checking purposes +-- and implemented later. + +---@type fun(any) +function log.trace(_) end +---@type fun(any) +function log.debug(_) end +---@type fun(any) +function log.info(_) end +---@type fun(any) +function log.warn(_) end +---@type fun(any) +function log.error(_) end local LARGE = 1e9 @@ -37,20 +44,22 @@ end local logfilename = vim.fn.tempname() .. "-rocks-nvim.log" ---Get the rocks.nvim log file path. +---@package ---@return string filepath function log.get_logfile() return logfilename end ---Open the rocks.nvim log file. +---@package function log.open_logfile() vim.cmd.e(log.get_logfile()) end local logfile, openerr ---- @private ---- Opens log file. Returns true if file is open, false on error ---- @return boolean +---@private +---Opens log file. Returns true if file is open, false on error +---@return boolean local function open_logfile() -- Try to open file only once if logfile then @@ -79,9 +88,10 @@ local function open_logfile() return true end ---- Set the log level ---- @param level (string|integer) The log level ---- @see vim.log.levels +---Set the log level +---@param level (string|integer) The log level +---@see vim.log.levels +---@package function log.set_level(level) local log_levels = vim.deepcopy(vim.log.levels) vim.tbl_add_reverse_lookup(log_levels) diff --git a/lua/rocks/operations.lua b/lua/rocks/operations.lua index fa76fc49..30d9fbb0 100644 --- a/lua/rocks/operations.lua +++ b/lua/rocks/operations.lua @@ -28,12 +28,34 @@ local progress = require("fidget.progress") local operations = {} +---@type RockHandler[] +local _handlers = {} + +---@param handler RockHandler +function operations.register_handler(handler) + table.insert(_handlers, handler) +end + +---@param spec RockSpec +---@return fun() | nil +local function get_sync_handler_callback(spec) + return vim.iter(_handlers) + :map(function(handler) + ---@cast handler RockHandler + local get_callback = handler.get_sync_callback + return get_callback and get_callback(spec) + end) + :find(function(callback) + return callback ~= nil + end) +end + ---@class (exact) Future ---@field wait fun() Wait in an async context. Does not block in a sync context ---@field wait_sync fun() Wait in a sync context ----@alias rock_config_table { [string]: Rock|string } ----@alias rock_table { [string]: Rock } +---@alias rock_config_table { [rock_name]: Rock|string } +---@alias rock_table { [rock_name]: Rock } ---Decode the user rocks from rocks.toml, creating a default config file if it does not exist ---@return { rocks?: rock_config_table, plugins?: rock_config_table } @@ -180,7 +202,7 @@ end) --- - Installs missing rocks --- - Ensures that the correct versions are installed --- - Uninstalls unneeded rocks ----@param user_rocks? { [string]: Rock|string } loaded from rocks.toml if `nil` +---@param user_rocks? table loaded from rocks.toml if `nil` operations.sync = function(user_rocks) log.info("syncing...") nio.run(function() @@ -203,7 +225,11 @@ operations.sync = function(user_rocks) }) ) end - + local function report_progress(message) + progress_handle:report({ + message = message, + }) + end if user_rocks == nil then -- Read or create a new config file and decode it -- NOTE: This does not use parse_user_rocks because we decode with toml, not toml-edit @@ -217,13 +243,16 @@ operations.sync = function(user_rocks) for name, data in pairs(user_rocks) do -- TODO(vhyrro): Good error checking if type(data) == "string" then + ---@type RockSpec user_rocks[name] = { name = name, version = data, } + else + user_rocks[name].name = name end end - ---@cast user_rocks rock_table + ---@cast user_rocks table local installed_rocks = state.installed_rocks() @@ -233,6 +262,8 @@ operations.sync = function(user_rocks) ---@diagnostic disable-next-line: invisible local key_list = nio.fn.keys(vim.tbl_deep_extend("force", installed_rocks, user_rocks)) + local external_actions = vim.empty_dict() + ---@cast external_actions rock_handler_callback[] local to_install = vim.empty_dict() ---@cast to_install string[] local to_updowngrade = vim.empty_dict() @@ -240,26 +271,38 @@ operations.sync = function(user_rocks) local to_prune = vim.empty_dict() ---@cast to_prune string[] for _, key in ipairs(key_list) do - if user_rocks[key] and not installed_rocks[key] then + local user_rock = user_rocks[key] + local callback = user_rock and get_sync_handler_callback(user_rock) + if callback then + table.insert(external_actions, callback) + elseif user_rocks and not installed_rocks[key] then table.insert(to_install, key) elseif - user_rocks[key] + user_rock + and user_rock.version and installed_rocks[key] - and user_rocks[key].version ~= installed_rocks[key].version + and user_rock.version ~= installed_rocks[key].version then table.insert(to_updowngrade, key) - elseif not user_rocks[key] and installed_rocks[key] then + elseif not user_rock and installed_rocks[key] then table.insert(to_prune, key) end end local ct = 1 - local action_count = #to_install + #to_updowngrade + #to_prune + ---@diagnostic disable-next-line: invisible + local action_count = #to_install + #to_updowngrade + #to_prune + #external_actions local function get_progress_percentage() return get_percentage(ct, action_count) end + -- Sync actions handled by external modules that have registered handlers + for _, callback in ipairs(external_actions) do + ct = ct + 1 + callback(report_progress, report_error) + end + for _, key in ipairs(to_install) do nio.scheduler() progress_handle:report({ @@ -328,6 +371,14 @@ operations.sync = function(user_rocks) end end + -- Tell external handlers to prune their rocks + for _, handler in pairs(_handlers) do + local callback = handler.get_prune_callback(user_rocks) + if callback then + callback(report_progress, report_error) + end + end + ---@type string[] local prunable_rocks = vim.iter(to_prune) :filter(function(key) diff --git a/nix/test-overlay.nix b/nix/test-overlay.nix index 8996dd3b..bd701011 100644 --- a/nix/test-overlay.nix +++ b/nix/test-overlay.nix @@ -33,7 +33,7 @@ ]; text = '' mkdir -p doc - lemmy-help lua/rocks/{init,commands,config/init,api}.lua > doc/rocks.txt + lemmy-help lua/rocks/{init,commands,config/init,api,log}.lua > doc/rocks.txt ''; }; in {