* fix(diff): preserve due/rec when absent from buffer line Problem: `diff.apply` overwrites `task.due` and `task.recur` with `nil` whenever those fields aren't present as inline tokens in the buffer line. Because metadata is rendered as virtual text (never in the line text), every description edit silently clears due dates and recurrence rules. Solution: Only update `due`, `recur`, and `recur_mode` in the existing- task branch when the parsed entry actually contains them (non-nil). Users can still set/change these inline by typing `due:<date>` or `rec:<rule>`; clearing them requires `:Pending edit <id> -due`. * refactor: remove project-local store discovery Problem: `store.resolve_path()` searched upward for `.pending.json`, silently splitting task data across multiple files depending on CWD. Solution: `resolve_path()` now always returns `config.get().data_path`. Remove `M.init()` and the `:Pending init` command and tab-completion entry. Remove the project-local health message. * refactor: extract log.lua, standardise [pending.nvim]: prefix Problem: Notifications were scattered across files using bare `vim.notify` with inconsistent `pending.nvim: ` prefixes, and the `debug` guard in `textobj.lua` and `init.lua` was duplicated inline. Solution: Add `lua/pending/log.lua` with `info`, `warn`, `error`, and `debug` functions (prefix `[pending.nvim]: `). `log.debug` only fires when `config.debug = true` or the optional `override` param is `true`. Replace all `vim.notify` callsites and remove inline debug guards. * feat(parse): configurable input date formats Problem: `due:` only accepted ISO `YYYY-MM-DD` and built-in keywords; users expecting locale-style dates like `03/15/2026` or `15-Mar-2026` had no way to configure alternative input formats. Solution: Add `input_date_formats` config field (string[]). Each entry is a strftime-like format string supporting `%Y`, `%y`, `%m`, `%d`, `%e`, `%b`, `%B`. Formats are tried in order after built-in keywords fail. When no year specifier is present the current or next year is inferred. Update vimdoc and add 8 parse_spec tests.
120 lines
3.1 KiB
Lua
120 lines
3.1 KiB
Lua
require('spec.helpers')
|
|
|
|
local config = require('pending.config')
|
|
|
|
describe('sync', function()
|
|
local tmpdir
|
|
local pending
|
|
|
|
before_each(function()
|
|
tmpdir = vim.fn.tempname()
|
|
vim.fn.mkdir(tmpdir, 'p')
|
|
vim.g.pending = { data_path = tmpdir .. '/tasks.json' }
|
|
config.reset()
|
|
package.loaded['pending'] = nil
|
|
pending = require('pending')
|
|
end)
|
|
|
|
after_each(function()
|
|
vim.fn.delete(tmpdir, 'rf')
|
|
vim.g.pending = nil
|
|
config.reset()
|
|
package.loaded['pending'] = nil
|
|
end)
|
|
|
|
describe('dispatch', function()
|
|
it('errors on unknown subcommand', function()
|
|
local msg
|
|
local orig = vim.notify
|
|
vim.notify = function(m, level)
|
|
if level == vim.log.levels.ERROR then
|
|
msg = m
|
|
end
|
|
end
|
|
pending.command('notreal')
|
|
vim.notify = orig
|
|
assert.are.equal('[pending.nvim]: Unknown Pending subcommand: notreal', msg)
|
|
end)
|
|
|
|
it('errors on unknown action for valid 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.command('gcal notreal')
|
|
vim.notify = orig
|
|
assert.are.equal("[pending.nvim]: gcal backend has no 'notreal' action", msg)
|
|
end)
|
|
|
|
it('lists actions when action is omitted', function()
|
|
local msg = nil
|
|
local orig = vim.notify
|
|
vim.notify = function(m)
|
|
msg = m
|
|
end
|
|
pending.command('gcal')
|
|
vim.notify = orig
|
|
assert.is_not_nil(msg)
|
|
assert.is_truthy(msg:find('push'))
|
|
end)
|
|
|
|
it('routes explicit push action', function()
|
|
local called = false
|
|
local gcal = require('pending.sync.gcal')
|
|
local orig_push = gcal.push
|
|
gcal.push = function()
|
|
called = true
|
|
end
|
|
pending.command('gcal push')
|
|
gcal.push = orig_push
|
|
assert.is_true(called)
|
|
end)
|
|
|
|
it('routes auth action', function()
|
|
local called = false
|
|
local gcal = require('pending.sync.gcal')
|
|
local orig_auth = gcal.auth
|
|
gcal.auth = function()
|
|
called = true
|
|
end
|
|
pending.command('gcal auth')
|
|
gcal.auth = orig_auth
|
|
assert.is_true(called)
|
|
end)
|
|
end)
|
|
|
|
it('works with sync.gcal config', function()
|
|
config.reset()
|
|
vim.g.pending = {
|
|
data_path = tmpdir .. '/tasks.json',
|
|
sync = { gcal = { client_id = 'test-id' } },
|
|
}
|
|
local cfg = config.get()
|
|
assert.are.equal('test-id', cfg.sync.gcal.client_id)
|
|
end)
|
|
|
|
describe('gcal module', function()
|
|
it('has name field', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('gcal', gcal.name)
|
|
end)
|
|
|
|
it('has auth function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('function', type(gcal.auth))
|
|
end)
|
|
|
|
it('has push function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('function', type(gcal.push))
|
|
end)
|
|
|
|
it('has health function', function()
|
|
local gcal = require('pending.sync.gcal')
|
|
assert.are.equal('function', type(gcal.health))
|
|
end)
|
|
end)
|
|
end)
|