refactor(cli): promote sync backends to top-level subcommands
Problem: `:Pending sync gtasks auth` required an extra `sync` keyword
that added no value and made the command unnecessarily verbose.
Solution: route `gtasks` and `gcal` as top-level `:Pending` subcommands
via `SYNC_BACKEND_SET` lookup. Tab completion introspects backend
modules for available actions instead of hardcoding `{ 'auth', 'sync' }`.
This commit is contained in:
parent
27647d0575
commit
ffc588ccf9
3 changed files with 50 additions and 64 deletions
|
|
@ -523,14 +523,19 @@ function M.add(text)
|
|||
vim.notify('Pending added: ' .. description)
|
||||
end
|
||||
|
||||
---@type string[]
|
||||
local SYNC_BACKENDS = { 'gcal', 'gtasks' }
|
||||
|
||||
---@type table<string, true>
|
||||
local SYNC_BACKEND_SET = {}
|
||||
for _, b in ipairs(SYNC_BACKENDS) do
|
||||
SYNC_BACKEND_SET[b] = true
|
||||
end
|
||||
|
||||
---@param backend_name string
|
||||
---@param action? string
|
||||
---@return nil
|
||||
function M.sync(backend_name, action)
|
||||
if not backend_name or backend_name == '' then
|
||||
vim.notify('Usage: :Pending sync <backend> [action]', vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
local function run_sync(backend_name, action)
|
||||
action = (action and action ~= '') and action or 'sync'
|
||||
local ok, backend = pcall(require, 'pending.sync.' .. backend_name)
|
||||
if not ok then
|
||||
|
|
@ -835,9 +840,9 @@ function M.command(args)
|
|||
elseif cmd == 'edit' then
|
||||
local id_str, edit_rest = rest:match('^(%S+)%s*(.*)')
|
||||
M.edit(id_str, edit_rest)
|
||||
elseif cmd == 'sync' then
|
||||
local backend, action = rest:match('^(%S+)%s*(.*)')
|
||||
M.sync(backend, action)
|
||||
elseif SYNC_BACKEND_SET[cmd] then
|
||||
local action = rest:match('^(%S+)') or 'sync'
|
||||
run_sync(cmd, action)
|
||||
elseif cmd == 'archive' then
|
||||
local d = rest ~= '' and tonumber(rest) or nil
|
||||
M.archive(d)
|
||||
|
|
@ -854,4 +859,14 @@ function M.command(args)
|
|||
end
|
||||
end
|
||||
|
||||
---@return string[]
|
||||
function M.sync_backends()
|
||||
return SYNC_BACKENDS
|
||||
end
|
||||
|
||||
---@return table<string, true>
|
||||
function M.sync_backend_set()
|
||||
return SYNC_BACKEND_SET
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
|
|||
|
|
@ -166,7 +166,12 @@ end, {
|
|||
bar = true,
|
||||
nargs = '*',
|
||||
complete = function(arg_lead, cmd_line)
|
||||
local subcmds = { 'add', 'archive', 'due', 'edit', 'filter', 'init', 'sync', 'undo' }
|
||||
local pending = require('pending')
|
||||
local subcmds = { 'add', 'archive', 'due', 'edit', 'filter', 'init', 'undo' }
|
||||
for _, b in ipairs(pending.sync_backends()) do
|
||||
table.insert(subcmds, b)
|
||||
end
|
||||
table.sort(subcmds)
|
||||
if not cmd_line:match('^Pending%s+%S') then
|
||||
return filter_candidates(arg_lead, subcmds)
|
||||
end
|
||||
|
|
@ -198,33 +203,25 @@ end, {
|
|||
if cmd_line:match('^Pending%s+edit') then
|
||||
return complete_edit(arg_lead, cmd_line)
|
||||
end
|
||||
if cmd_line:match('^Pending%s+sync') then
|
||||
local after_sync = cmd_line:match('^Pending%s+sync%s+(.*)')
|
||||
if not after_sync then
|
||||
local backend_set = pending.sync_backend_set()
|
||||
local matched_backend = cmd_line:match('^Pending%s+(%S+)')
|
||||
if matched_backend and backend_set[matched_backend] then
|
||||
local after_backend = cmd_line:match('^Pending%s+%S+%s+(.*)')
|
||||
if not after_backend then
|
||||
return {}
|
||||
end
|
||||
local parts = {}
|
||||
for part in after_sync:gmatch('%S+') do
|
||||
table.insert(parts, part)
|
||||
local ok, mod = pcall(require, 'pending.sync.' .. matched_backend)
|
||||
if not ok then
|
||||
return {}
|
||||
end
|
||||
local trailing_space = after_sync:match('%s$')
|
||||
if #parts == 0 or (#parts == 1 and not trailing_space) then
|
||||
local backends = {}
|
||||
local pattern = vim.fn.globpath(vim.o.runtimepath, 'lua/pending/sync/*.lua', false, true)
|
||||
for _, path in ipairs(pattern) do
|
||||
local name = vim.fn.fnamemodify(path, ':t:r')
|
||||
table.insert(backends, name)
|
||||
local actions = {}
|
||||
for k, v in pairs(mod) do
|
||||
if type(v) == 'function' and k:sub(1, 1) ~= '_' then
|
||||
table.insert(actions, k)
|
||||
end
|
||||
table.sort(backends)
|
||||
return filter_candidates(arg_lead, backends)
|
||||
end
|
||||
if #parts == 1 and trailing_space then
|
||||
return filter_candidates(arg_lead, { 'auth', 'sync' })
|
||||
end
|
||||
if #parts >= 2 and not trailing_space then
|
||||
return filter_candidates(arg_lead, { 'auth', 'sync' })
|
||||
end
|
||||
return {}
|
||||
table.sort(actions)
|
||||
return filter_candidates(arg_lead, actions)
|
||||
end
|
||||
return {}
|
||||
end,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('sync', function()
|
|||
end)
|
||||
|
||||
describe('dispatch', function()
|
||||
it('errors on bare :Pending sync with no backend', function()
|
||||
it('errors on unknown subcommand', function()
|
||||
local msg
|
||||
local orig = vim.notify
|
||||
vim.notify = function(m, level)
|
||||
|
|
@ -31,35 +31,9 @@ describe('sync', function()
|
|||
msg = m
|
||||
end
|
||||
end
|
||||
pending.sync(nil)
|
||||
pending.command('notreal')
|
||||
vim.notify = orig
|
||||
assert.are.equal('Usage: :Pending sync <backend> [action]', msg)
|
||||
end)
|
||||
|
||||
it('errors on empty backend string', function()
|
||||
local msg
|
||||
local orig = vim.notify
|
||||
vim.notify = function(m, level)
|
||||
if level == vim.log.levels.ERROR then
|
||||
msg = m
|
||||
end
|
||||
end
|
||||
pending.sync('')
|
||||
vim.notify = orig
|
||||
assert.are.equal('Usage: :Pending sync <backend> [action]', msg)
|
||||
end)
|
||||
|
||||
it('errors on unknown 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.sync('notreal')
|
||||
vim.notify = orig
|
||||
assert.are.equal('Unknown sync backend: notreal', msg)
|
||||
assert.are.equal('Unknown Pending subcommand: notreal', msg)
|
||||
end)
|
||||
|
||||
it('errors on unknown action for valid backend', function()
|
||||
|
|
@ -70,7 +44,7 @@ describe('sync', function()
|
|||
msg = m
|
||||
end
|
||||
end
|
||||
pending.sync('gcal', 'notreal')
|
||||
pending.command('gcal notreal')
|
||||
vim.notify = orig
|
||||
assert.are.equal("gcal backend has no 'notreal' action", msg)
|
||||
end)
|
||||
|
|
@ -82,7 +56,7 @@ describe('sync', function()
|
|||
gcal.sync = function()
|
||||
called = true
|
||||
end
|
||||
pending.sync('gcal')
|
||||
pending.command('gcal')
|
||||
gcal.sync = orig_sync
|
||||
assert.is_true(called)
|
||||
end)
|
||||
|
|
@ -94,7 +68,7 @@ describe('sync', function()
|
|||
gcal.sync = function()
|
||||
called = true
|
||||
end
|
||||
pending.sync('gcal', 'sync')
|
||||
pending.command('gcal sync')
|
||||
gcal.sync = orig_sync
|
||||
assert.is_true(called)
|
||||
end)
|
||||
|
|
@ -106,7 +80,7 @@ describe('sync', function()
|
|||
gcal.auth = function()
|
||||
called = true
|
||||
end
|
||||
pending.sync('gcal', 'auth')
|
||||
pending.command('gcal auth')
|
||||
gcal.auth = orig_auth
|
||||
assert.is_true(called)
|
||||
end)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue