diff --git a/lua/pending/init.lua b/lua/pending/init.lua index 12b6a7e..f4f7264 100644 --- a/lua/pending/init.lua +++ b/lua/pending/init.lua @@ -523,14 +523,19 @@ function M.add(text) vim.notify('Pending added: ' .. description) end +---@type string[] +local SYNC_BACKENDS = { 'gcal', 'gtasks' } + +---@type table +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 [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 +function M.sync_backend_set() + return SYNC_BACKEND_SET +end + return M diff --git a/plugin/pending.lua b/plugin/pending.lua index f533dcf..13f16d3 100644 --- a/plugin/pending.lua +++ b/plugin/pending.lua @@ -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, diff --git a/spec/sync_spec.lua b/spec/sync_spec.lua index 9e24e7d..ce38635 100644 --- a/spec/sync_spec.lua +++ b/spec/sync_spec.lua @@ -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 [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 [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)