From 87679e98571a8b125d7108201d436bcf7e97fb0a Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Thu, 5 Mar 2026 12:18:57 -0500 Subject: [PATCH] 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:` or `rec:`; clearing them requires `:Pending edit -due`. --- lua/pending/diff.lua | 18 ++++++++++-------- spec/diff_spec.lua | 21 +++++++++++++++++---- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lua/pending/diff.lua b/lua/pending/diff.lua index 7ebbfe1..5df332f 100644 --- a/lua/pending/diff.lua +++ b/lua/pending/diff.lua @@ -121,17 +121,19 @@ function M.apply(lines, s, hidden_ids) task.priority = entry.priority changed = true end - if task.due ~= entry.due then + if entry.due ~= nil and task.due ~= entry.due then task.due = entry.due changed = true end - if task.recur ~= entry.rec then - task.recur = entry.rec - changed = true - end - if task.recur_mode ~= entry.rec_mode then - task.recur_mode = entry.rec_mode - changed = true + if entry.rec ~= nil then + if task.recur ~= entry.rec then + task.recur = entry.rec + changed = true + end + if task.recur_mode ~= entry.rec_mode then + task.recur_mode = entry.rec_mode + changed = true + end end if entry.status and task.status ~= entry.status then task.status = entry.status diff --git a/spec/diff_spec.lua b/spec/diff_spec.lua index c2a0406..01d8aac 100644 --- a/spec/diff_spec.lua +++ b/spec/diff_spec.lua @@ -199,7 +199,7 @@ describe('diff', function() assert.are.equal(modified_after_first, task.modified) end) - it('clears due when removed from buffer line', function() + it('preserves due when not present in buffer line', function() s:add({ description = 'Pay bill', due = '2026-03-15' }) s:save() local lines = { @@ -209,7 +209,20 @@ describe('diff', function() diff.apply(lines, s) s:load() local task = s:get(1) - assert.is_nil(task.due) + assert.are.equal('2026-03-15', task.due) + end) + + it('updates due when inline token is present', function() + s:add({ description = 'Pay bill', due = '2026-03-15' }) + s:save() + local lines = { + '# Inbox', + '/1/- [ ] Pay bill due:2026-04-01', + } + diff.apply(lines, s) + s:load() + local task = s:get(1) + assert.are.equal('2026-04-01', task.due) end) it('stores recur field on new tasks from buffer', function() @@ -237,7 +250,7 @@ describe('diff', function() assert.are.equal('weekly', task.recur) end) - it('clears recur when token removed from line', function() + it('preserves recur when not present in buffer line', function() s:add({ description = 'Task', recur = 'daily' }) s:save() local lines = { @@ -247,7 +260,7 @@ describe('diff', function() diff.apply(lines, s) s:load() local task = s:get(1) - assert.is_nil(task.recur) + assert.are.equal('daily', task.recur) end) it('parses rec: with completion mode prefix', function()