diff --git a/doc/pending.txt b/doc/pending.txt index 3052d15..9a62c3d 100644 --- a/doc/pending.txt +++ b/doc/pending.txt @@ -664,7 +664,7 @@ On `:w`, the description becomes `Buy milk`, the due date is stored as placed under the `Errands` category header. Only the first occurrence of each metadata type is consumed — duplicate -tokens are silently dropped. +tokens are dropped with a warning. Omnifunc completion is available for `due:`, `cat:`, and `rec:` token types. In insert mode, type the token prefix and press `` to see diff --git a/lua/pending/parse.lua b/lua/pending/parse.lua index 9fd179e..a85d7af 100644 --- a/lua/pending/parse.lua +++ b/lua/pending/parse.lua @@ -1,5 +1,6 @@ local config = require('pending.config') local forge = require('pending.forge') +local log = require('pending.log') ---@class pending.Metadata ---@field due? string @@ -553,6 +554,8 @@ function M.body(text) if due_val and is_valid_datetime(due_val) then if not metadata.due then metadata.due = due_val + else + log.warn('duplicate ' .. dk .. ': token ignored: ' .. token) end consumed = true end @@ -563,6 +566,8 @@ function M.body(text) if resolved then if not metadata.due then metadata.due = resolved + else + log.warn('duplicate ' .. dk .. ': token ignored: ' .. token) end consumed = true end @@ -574,6 +579,8 @@ function M.body(text) if cat_val then if not metadata.category then metadata.category = cat_val + else + log.warn('duplicate ' .. ck .. ': token ignored: ' .. token) end consumed = true end @@ -585,6 +592,8 @@ function M.body(text) if not metadata.priority then local max = config.get().max_priority or 3 metadata.priority = math.min(#pri_bangs, max) + else + log.warn('duplicate priority token ignored: ' .. token) end consumed = true end @@ -602,6 +611,8 @@ function M.body(text) if not metadata.recur then metadata.recur_mode = rec_val:sub(1, 1) == '!' and 'completion' or nil metadata.recur = raw_spec + else + log.warn('duplicate ' .. rk .. ': token ignored: ' .. token) end consumed = true end diff --git a/spec/parse_spec.lua b/spec/parse_spec.lua index e02f1dc..b0a3f8e 100644 --- a/spec/parse_spec.lua +++ b/spec/parse_spec.lua @@ -48,16 +48,35 @@ describe('parse', function() assert.are.equal('Errands', meta.category) end) - it('first occurrence wins for duplicate keys', function() + it('first occurrence wins for duplicate keys and warns', function() + local warnings = {} + local orig = vim.notify + vim.notify = function(m, level) + if level == vim.log.levels.WARN then + table.insert(warnings, m) + end + end local desc, meta = parse.body('Buy milk due:2026-03-15 due:2026-04-01') + vim.notify = orig assert.are.equal('Buy milk', desc) assert.are.equal('2026-03-15', meta.due) + assert.are.equal(1, #warnings) + assert.truthy(warnings[1]:find('duplicate', 1, true)) end) - it('drops identical duplicate metadata tokens', function() + it('drops identical duplicate metadata tokens and warns', function() + local warnings = {} + local orig = vim.notify + vim.notify = function(m, level) + if level == vim.log.levels.WARN then + table.insert(warnings, m) + end + end local desc, meta = parse.body('Buy milk due:tomorrow due:tomorrow') + vim.notify = orig assert.are.equal('Buy milk', desc) assert.are.equal(os.date('%Y-%m-%d', os.time() + 86400), meta.due) + assert.are.equal(1, #warnings) end) it('stops at non-meta token', function()