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:
Barrett Ruth 2026-03-05 00:59:00 -05:00
parent 27647d0575
commit ffc588ccf9
3 changed files with 50 additions and 64 deletions

View file

@ -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,