This commit is contained in:
Barrett Ruth 2026-02-25 13:06:20 -05:00
parent 7ebfcc63c3
commit 9c5d57bece
7 changed files with 80 additions and 53 deletions

View file

@ -32,11 +32,31 @@ end
---@return string[] ---@return string[]
local function date_completions() local function date_completions()
return { return {
'today', 'tomorrow', 'yesterday', 'today',
'+1d', '+2d', '+3d', '+1w', '+2w', '+1m', 'tomorrow',
'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', 'yesterday',
'eod', 'eow', 'eom', 'eoq', 'eoy', '+1d',
'sow', 'som', 'soq', 'soy', '+2d',
'+3d',
'+1w',
'+2w',
'+1m',
'mon',
'tue',
'wed',
'thu',
'fri',
'sat',
'sun',
'eod',
'eow',
'eom',
'eoq',
'eoy',
'sow',
'som',
'soq',
'soy',
'later', 'later',
} }
end end

View file

@ -32,9 +32,7 @@ function M.check()
for _, task in ipairs(tasks) do for _, task in ipairs(tasks) do
if task.recur and not recur.validate(task.recur) then if task.recur and not recur.validate(task.recur) then
invalid_count = invalid_count + 1 invalid_count = invalid_count + 1
vim.health.warn( vim.health.warn('Task ' .. task.id .. ' has invalid recurrence spec: ' .. task.recur)
'Task ' .. task.id .. ' has invalid recurrence spec: ' .. task.recur
)
end end
end end
if invalid_count == 0 then if invalid_count == 0 then

View file

@ -130,7 +130,8 @@ function M.toggle_complete()
if task.recur and task.due then if task.recur and task.due then
local recur = require('pending.recur') local recur = require('pending.recur')
local mode = task.recur_mode or 'scheduled' local mode = task.recur_mode or 'scheduled'
local base = mode == 'completion' and os.date('%Y-%m-%d') --[[@as string]] or task.due local base = mode == 'completion' and os.date('%Y-%m-%d') --[[@as string]]
or task.due
local next_date = recur.next_due(base, task.recur, mode) local next_date = recur.next_due(base, task.recur, mode)
store.add({ store.add({
description = task.description, description = task.description,

View file

@ -45,9 +45,18 @@ local weekday_map = {
} }
local month_map = { local month_map = {
jan = 1, feb = 2, mar = 3, apr = 4, jan = 1,
may = 5, jun = 6, jul = 7, aug = 8, feb = 2,
sep = 9, oct = 10, nov = 11, dec = 12, mar = 3,
apr = 4,
may = 5,
jun = 6,
jul = 7,
aug = 8,
sep = 9,
oct = 10,
nov = 11,
dec = 12,
} }
---@param today osdate ---@param today osdate
@ -97,49 +106,31 @@ function M.resolve_date(text)
end end
if lower == 'som' then if lower == 'som' then
return os.date( return os.date('%Y-%m-%d', os.time({ year = today.year, month = today.month, day = 1 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = today.year, month = today.month, day = 1 })
) --[[@as string]]
end end
if lower == 'eom' then if lower == 'eom' then
return os.date( return os.date('%Y-%m-%d', os.time({ year = today.year, month = today.month + 1, day = 0 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = today.year, month = today.month + 1, day = 0 })
) --[[@as string]]
end end
if lower == 'soq' then if lower == 'soq' then
local q = math.ceil(today.month / 3) local q = math.ceil(today.month / 3)
local first_month = (q - 1) * 3 + 1 local first_month = (q - 1) * 3 + 1
return os.date( return os.date('%Y-%m-%d', os.time({ year = today.year, month = first_month, day = 1 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = today.year, month = first_month, day = 1 })
) --[[@as string]]
end end
if lower == 'eoq' then if lower == 'eoq' then
local q = math.ceil(today.month / 3) local q = math.ceil(today.month / 3)
local last_month = q * 3 local last_month = q * 3
return os.date( return os.date('%Y-%m-%d', os.time({ year = today.year, month = last_month + 1, day = 0 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = today.year, month = last_month + 1, day = 0 })
) --[[@as string]]
end end
if lower == 'soy' then if lower == 'soy' then
return os.date( return os.date('%Y-%m-%d', os.time({ year = today.year, month = 1, day = 1 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = today.year, month = 1, day = 1 })
) --[[@as string]]
end end
if lower == 'eoy' then if lower == 'eoy' then
return os.date( return os.date('%Y-%m-%d', os.time({ year = today.year, month = 12, day = 31 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = today.year, month = 12, day = 31 })
) --[[@as string]]
end end
if lower == 'later' or lower == 'someday' then if lower == 'later' or lower == 'someday' then
@ -153,7 +144,9 @@ function M.resolve_date(text)
os.time({ os.time({
year = today.year, year = today.year,
month = today.month, month = today.month,
day = today.day + (tonumber(n) --[[@as integer]]), day = today.day + (
tonumber(n) --[[@as integer]]
),
}) })
) --[[@as string]] ) --[[@as string]]
end end
@ -165,7 +158,9 @@ function M.resolve_date(text)
os.time({ os.time({
year = today.year, year = today.year,
month = today.month, month = today.month,
day = today.day + (tonumber(n) --[[@as integer]]) * 7, day = today.day + (
tonumber(n) --[[@as integer]]
) * 7,
}) })
) --[[@as string]] ) --[[@as string]]
end end
@ -176,7 +171,9 @@ function M.resolve_date(text)
'%Y-%m-%d', '%Y-%m-%d',
os.time({ os.time({
year = today.year, year = today.year,
month = today.month + (tonumber(n) --[[@as integer]]), month = today.month + (
tonumber(n) --[[@as integer]]
),
day = today.day, day = today.day,
}) })
) --[[@as string]] ) --[[@as string]]
@ -189,7 +186,9 @@ function M.resolve_date(text)
os.time({ os.time({
year = today.year, year = today.year,
month = today.month, month = today.month,
day = today.day - (tonumber(n) --[[@as integer]]), day = today.day - (
tonumber(n) --[[@as integer]]
),
}) })
) --[[@as string]] ) --[[@as string]]
end end
@ -201,7 +200,9 @@ function M.resolve_date(text)
os.time({ os.time({
year = today.year, year = today.year,
month = today.month, month = today.month,
day = today.day - (tonumber(n) --[[@as integer]]) * 7, day = today.day - (
tonumber(n) --[[@as integer]]
) * 7,
}) })
) --[[@as string]] ) --[[@as string]]
end end
@ -243,10 +244,7 @@ function M.resolve_date(text)
if today.month >= target_month then if today.month >= target_month then
y = y + 1 y = y + 1
end end
return os.date( return os.date('%Y-%m-%d', os.time({ year = y, month = target_month, day = 1 })) --[[@as string]]
'%Y-%m-%d',
os.time({ year = y, month = target_month, day = 1 })
) --[[@as string]]
end end
local target_wday = weekday_map[lower] local target_wday = weekday_map[lower]

View file

@ -10,7 +10,12 @@ local M = {}
---@type table<string, pending.RecurSpec> ---@type table<string, pending.RecurSpec>
local named = { local named = {
daily = { freq = 'daily', interval = 1, from_completion = false }, daily = { freq = 'daily', interval = 1, from_completion = false },
weekdays = { freq = 'weekly', interval = 1, byday = { 'MO', 'TU', 'WE', 'TH', 'FR' }, from_completion = false }, weekdays = {
freq = 'weekly',
interval = 1,
byday = { 'MO', 'TU', 'WE', 'TH', 'FR' },
from_completion = false,
},
weekly = { freq = 'weekly', interval = 1, from_completion = false }, weekly = { freq = 'weekly', interval = 1, from_completion = false },
biweekly = { freq = 'weekly', interval = 2, from_completion = false }, biweekly = { freq = 'weekly', interval = 2, from_completion = false },
monthly = { freq = 'monthly', interval = 1, from_completion = false }, monthly = { freq = 'monthly', interval = 1, from_completion = false },

View file

@ -193,7 +193,8 @@ describe('parse', function()
it('returns last day of current month for eom', function() it('returns last day of current month for eom', function()
local today = os.date('*t') --[[@as osdate]] local today = os.date('*t') --[[@as osdate]]
local expected = os.date('%Y-%m-%d', os.time({ year = today.year, month = today.month + 1, day = 0 })) local expected =
os.date('%Y-%m-%d', os.time({ year = today.year, month = today.month + 1, day = 0 }))
local result = parse.resolve_date('eom') local result = parse.resolve_date('eom')
assert.are.equal(expected, result) assert.are.equal(expected, result)
end) end)
@ -211,7 +212,8 @@ describe('parse', function()
local today = os.date('*t') --[[@as osdate]] local today = os.date('*t') --[[@as osdate]]
local q = math.ceil(today.month / 3) local q = math.ceil(today.month / 3)
local last_month = q * 3 local last_month = q * 3
local expected = os.date('%Y-%m-%d', os.time({ year = today.year, month = last_month + 1, day = 0 })) local expected =
os.date('%Y-%m-%d', os.time({ year = today.year, month = last_month + 1, day = 0 }))
local result = parse.resolve_date('eoq') local result = parse.resolve_date('eoq')
assert.are.equal(expected, result) assert.are.equal(expected, result)
end) end)

View file

@ -151,11 +151,14 @@ describe('recur', function()
it('completion mode advances from today', function() it('completion mode advances from today', function()
local today = os.date('*t') --[[@as osdate]] local today = os.date('*t') --[[@as osdate]]
local expected = os.date('%Y-%m-%d', os.time({ local expected = os.date(
'%Y-%m-%d',
os.time({
year = today.year, year = today.year,
month = today.month, month = today.month,
day = today.day + 7, day = today.day + 7,
})) })
)
local result = recur.next_due('2020-01-01', 'weekly', 'completion') local result = recur.next_due('2020-01-01', 'weekly', 'completion')
assert.are.equal(expected, result) assert.are.equal(expected, result)
end) end)