fix: revert dev

This commit is contained in:
Barrett Ruth 2026-03-13 17:58:49 -04:00
parent f846155ee5
commit 2b75843dab
4 changed files with 160 additions and 12 deletions

View file

@ -59,7 +59,7 @@ function M.check()
end
local sync_paths = vim.fn.globpath(vim.o.runtimepath, 'lua/pending/sync/*.lua', false, true)
if #sync_paths == 0 then
if #sync_paths == 0 and vim.tbl_isempty(require('pending').registered_backends()) then
vim.health.info('No sync backends found')
else
for _, path in ipairs(sync_paths) do
@ -70,6 +70,12 @@ function M.check()
backend.health()
end
end
for rname, rbackend in pairs(require('pending').registered_backends()) do
if type(rbackend.health) == 'function' then
vim.health.start('pending.nvim: sync/' .. rname)
rbackend.health()
end
end
end
end

View file

@ -1141,18 +1141,60 @@ end
---@class pending.SyncBackend
---@field name string
---@field auth fun(): nil
---@field auth? fun(sub_action?: string): nil
---@field push? fun(): nil
---@field pull? fun(): nil
---@field sync? fun(): nil
---@field health? fun(): nil
---@type table<string, pending.SyncBackend>
local _registered_backends = {}
---@type string[]?
local _sync_backends = nil
---@type table<string, true>?
local _sync_backend_set = nil
---@param name string
---@return pending.SyncBackend?
function M.resolve_backend(name)
if _registered_backends[name] then
return _registered_backends[name]
end
local ok, mod = pcall(require, 'pending.sync.' .. name)
if ok and type(mod) == 'table' and mod.name then
return mod
end
return nil
end
---@param backend pending.SyncBackend
---@return nil
function M.register_backend(backend)
if type(backend) ~= 'table' or type(backend.name) ~= 'string' or backend.name == '' then
log.error('register_backend: backend must have a non-empty `name` field')
return
end
local builtin_ok, builtin = pcall(require, 'pending.sync.' .. backend.name)
if builtin_ok and type(builtin) == 'table' and builtin.name then
log.error('register_backend: backend `' .. backend.name .. '` already exists as a built-in')
return
end
if _registered_backends[backend.name] then
log.error('register_backend: backend `' .. backend.name .. '` is already registered')
return
end
_registered_backends[backend.name] = backend
_sync_backends = nil
_sync_backend_set = nil
end
---@return table<string, pending.SyncBackend>
function M.registered_backends()
return _registered_backends
end
---@return string[], table<string, true>
local function discover_backends()
if _sync_backends then
@ -1169,6 +1211,12 @@ local function discover_backends()
_sync_backend_set[mod.name] = true
end
end
for name, _ in pairs(_registered_backends) do
if not _sync_backend_set[name] then
table.insert(_sync_backends, name)
_sync_backend_set[name] = true
end
end
table.sort(_sync_backends)
return _sync_backends, _sync_backend_set
end
@ -1177,8 +1225,8 @@ end
---@param action? string
---@return nil
local function run_sync(backend_name, action)
local ok, backend = pcall(require, 'pending.sync.' .. backend_name)
if not ok then
local backend = M.resolve_backend(backend_name)
if not backend then
log.error('Unknown sync backend: ' .. backend_name)
return
end
@ -1543,8 +1591,8 @@ function M.auth(args)
local backends_list = discover_backends()
local auth_backends = {}
for _, name in ipairs(backends_list) do
local ok, mod = pcall(require, 'pending.sync.' .. name)
if ok and type(mod.auth) == 'function' then
local mod = M.resolve_backend(name)
if mod and type(mod.auth) == 'function' then
table.insert(auth_backends, { name = name, mod = mod })
end
end

View file

@ -304,8 +304,8 @@ end, {
if #parts == 0 or (#parts == 1 and not trailing) then
local auth_names = {}
for _, b in ipairs(pending.sync_backends()) do
local ok, mod = pcall(require, 'pending.sync.' .. b)
if ok and type(mod.auth) == 'function' then
local mod = pending.resolve_backend(b)
if mod and type(mod.auth) == 'function' then
table.insert(auth_names, b)
end
end
@ -313,8 +313,8 @@ end, {
end
local backend_name = parts[1]
if #parts == 1 or (#parts == 2 and not trailing) then
local ok, mod = pcall(require, 'pending.sync.' .. backend_name)
if ok and type(mod.auth_complete) == 'function' then
local mod = pending.resolve_backend(backend_name)
if mod and type(mod.auth_complete) == 'function' then
return filter_candidates(arg_lead, mod.auth_complete())
end
return {}
@ -328,8 +328,8 @@ end, {
if not after_backend then
return {}
end
local ok, mod = pcall(require, 'pending.sync.' .. matched_backend)
if not ok then
local mod = pending.resolve_backend(matched_backend)
if not mod then
return {}
end
local actions = {}

View file

@ -124,6 +124,100 @@ describe('sync', function()
end)
end)
describe('register_backend', function()
it('registers a custom backend', function()
pending.register_backend({ name = 'custom', pull = function() end })
local set = pending.sync_backend_set()
assert.is_true(set['custom'] == true)
assert.is_true(vim.tbl_contains(pending.sync_backends(), 'custom'))
end)
it('rejects backend without name', function()
local msg
local orig = vim.notify
vim.notify = function(m, level)
if level == vim.log.levels.ERROR then
msg = m
end
end
pending.register_backend({})
vim.notify = orig
assert.truthy(msg and msg:find('non%-empty'))
end)
it('rejects backend with empty name', function()
local msg
local orig = vim.notify
vim.notify = function(m, level)
if level == vim.log.levels.ERROR then
msg = m
end
end
pending.register_backend({ name = '' })
vim.notify = orig
assert.truthy(msg and msg:find('non%-empty'))
end)
it('rejects duplicate of built-in backend', function()
local msg
local orig = vim.notify
vim.notify = function(m, level)
if level == vim.log.levels.ERROR then
msg = m
end
end
pending.register_backend({ name = 'gcal' })
vim.notify = orig
assert.truthy(msg and msg:find('already exists'))
end)
it('rejects duplicate registered backend', function()
pending.register_backend({ name = 'dup_test', pull = function() end })
local msg
local orig = vim.notify
vim.notify = function(m, level)
if level == vim.log.levels.ERROR then
msg = m
end
end
pending.register_backend({ name = 'dup_test' })
vim.notify = orig
assert.truthy(msg and msg:find('already registered'))
end)
end)
describe('resolve_backend', function()
it('resolves built-in backend', function()
local mod = pending.resolve_backend('gcal')
assert.is_not_nil(mod)
assert.are.equal('gcal', mod.name)
end)
it('resolves registered backend', function()
local custom = { name = 'resolve_test', pull = function() end }
pending.register_backend(custom)
local mod = pending.resolve_backend('resolve_test')
assert.is_not_nil(mod)
assert.are.equal('resolve_test', mod.name)
end)
it('returns nil for unknown backend', function()
assert.is_nil(pending.resolve_backend('nonexistent_xyz'))
end)
it('dispatches command to registered backend', function()
local called = false
pending.register_backend({
name = 'cmd_test',
pull = function()
called = true
end,
})
pending.command('cmd_test pull')
assert.is_true(called)
end)
end)
describe('auto-discovery', function()
it('discovers gcal and gtasks backends', function()
local backends = pending.sync_backends()