From 7ebfcc63c3e5a053043414e6bab222b692128cc4 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Wed, 25 Feb 2026 13:04:46 -0500 Subject: [PATCH] docs: document recurrence, expanded dates, omnifunc, new config Problem: the vimdoc does not cover recurrence, expanded date syntax, omnifunc completion, or the new config fields. Solution: add DATE INPUT and RECURRENCE sections, update INLINE METADATA, COMMANDS, CONFIGURATION, HIGHLIGHT GROUPS, HEALTH CHECK, and DATA FORMAT. Expand the help popup with recurrence patterns and new date tokens. Add recurrence validation to healthcheck. --- doc/pending.txt | 122 +++++++++++++++++++++++++++++++++++++---- lua/pending/health.lua | 13 +++++ 2 files changed, 124 insertions(+), 11 deletions(-) diff --git a/doc/pending.txt b/doc/pending.txt index 4eb8e40..e9515d9 100644 --- a/doc/pending.txt +++ b/doc/pending.txt @@ -30,13 +30,16 @@ concealed tokens and are never visible during editing. Features: ~ - Oil-style buffer editing: standard Vim motions for all task operations -- Inline metadata syntax: `due:` and `cat:` tokens parsed on `:w` -- Relative date input: `today`, `tomorrow`, `+Nd`, weekday names +- Inline metadata syntax: `due:`, `cat:`, and `rec:` tokens parsed on `:w` +- Relative date input: `today`, `tomorrow`, `+Nd`, `+Nw`, `+Nm`, weekday + names, month names, ordinals, and more +- Recurring tasks with automatic next-date spawning on completion - Two views: category (default) and priority flat list - Multi-level undo (up to 20 `:w` saves, session-only) - Quick-add from the command line with `:Pending add` - Quickfix list of overdue/due-today tasks via `:Pending due` - Foldable category sections (`zc`/`zo`) in category view +- Omnifunc completion for `cat:`, `due:`, and `rec:` tokens (``) - Google Calendar one-way push via OAuth PKCE ============================================================================== @@ -95,20 +98,18 @@ parsed from the right and consumed until a non-metadata token is reached. Supported tokens: ~ `due:YYYY-MM-DD` Set a due date using an absolute date. - `due:today` Resolve to today's date. - `due:tomorrow` Resolve to tomorrow's date. - `due:+Nd` Resolve to N days from today (e.g. `due:+3d`). - `due:mon` Resolve to the next occurrence of that weekday. - Supported: `sun` `mon` `tue` `wed` `thu` `fri` `sat` + `due:` Resolve a named date (see |pending-dates| below). `cat:Name` Move the task to the named category on save. + `rec:` Set a recurrence rule (see |pending-recurrence|). The token name for due dates defaults to `due` and is configurable via -`date_syntax` in |pending-config|. If `date_syntax` is set to `by`, write -`by:2026-03-15` instead. +`date_syntax` in |pending-config|. The token name for recurrence defaults to +`rec` and is configurable via `recur_syntax`. Example: > Buy milk due:2026-03-15 cat:Errands + Take out trash due:monday rec:weekly < On `:w`, the description becomes `Buy milk`, the due date is stored as @@ -116,8 +117,87 @@ On `:w`, the description becomes `Buy milk`, the due date is stored as placed under the `Errands` category header. Parsing stops at the first token that is not a recognised metadata token. -Repeated tokens of the same type also stop parsing — only one `due:` and one -`cat:` per task line are consumed. +Repeated tokens of the same type also stop parsing — only one `due:`, one +`cat:`, and one `rec:` per task line are consumed. + +Omnifunc completion is available for all three token types. In insert mode, +type `due:`, `cat:`, or `rec:` and press `` to see suggestions. + +============================================================================== +DATE INPUT *pending-dates* + +Named dates can be used anywhere a date is accepted: the `due:` inline +token, the `D` prompt, and `:Pending add`. + + Token Resolves to ~ + ----- ----------- + `today` Today's date + `tomorrow` Tomorrow's date + `yesterday` Yesterday's date + `eod` Today (end of day semantics) + `+Nd` N days from today (e.g. `+3d`) + `+Nw` N weeks from today (e.g. `+2w`) + `+Nm` N months from today (e.g. `+1m`) + `-Nd` N days ago (e.g. `-2d`) + `-Nw` N weeks ago (e.g. `-1w`) + `mon`–`sun` Next occurrence of that weekday + `jan`–`dec` 1st of next occurrence of that month + `1st`–`31st` Next occurrence of that day-of-month + `sow` / `eow` Monday / Sunday of current week + `som` / `eom` First / last day of current month + `soq` / `eoq` First / last day of current quarter + `soy` / `eoy` January 1 / December 31 of current year + `later` / `someday` Sentinel date (default: `9999-12-30`) + +============================================================================== +RECURRENCE *pending-recurrence* + +Tasks can recur on a schedule. Add a `rec:` token to set recurrence: > + + - [ ] Take out trash due:monday rec:weekly + - [ ] Pay rent due:2026-03-01 rec:monthly + - [ ] Standup due:tomorrow rec:weekdays +< + +When a recurring task is marked done with ``: +1. The current task stays as done (preserving history). +2. A new pending task is created with the same description, category, + priority, and recurrence — with the due date advanced to the next + occurrence. + +Shorthand patterns: ~ + + Pattern Meaning ~ + ------- ------- + `daily` Every day + `weekdays` Monday through Friday + `weekly` Every week + `biweekly` Every 2 weeks (alias: `2w`) + `monthly` Every month + `quarterly` Every 3 months (alias: `3m`) + `yearly` Every year (alias: `annual`) + `Nd` Every N days (e.g. `3d`) + `Nw` Every N weeks (e.g. `2w`) + `Nm` Every N months (e.g. `6m`) + `Ny` Every N years (e.g. `2y`) + +For patterns the shorthand cannot express, use a raw RRULE fragment: > + rec:FREQ=MONTHLY;BYDAY=1MO +< + +Completion-based recurrence: ~ *pending-recur-completion* +By default, recurrence is schedule-based: the next due date advances from the +original schedule, skipping to the next future occurrence. Prefix the pattern +with `!` for completion-based mode, where the next due date advances from the +completion date: > + rec:!weekly +< +Schedule-based is like org-mode `++`; completion-based is like `.+`. + +Google Calendar: ~ +Recurrence patterns map directly to iCalendar RRULE strings for future GCal +sync support. Completion-based recurrence cannot be synced (it is inherently +local). ============================================================================== COMMANDS *pending-commands* @@ -135,6 +215,7 @@ COMMANDS *pending-commands* :Pending add Buy groceries due:2026-03-15 :Pending add School: Submit homework :Pending add Errands: Pick up dry cleaning due:fri + :Pending add Work: standup due:tomorrow rec:weekdays < If the buffer is currently open it is re-rendered after the add. @@ -242,6 +323,8 @@ loads: >lua default_category = 'Inbox', date_format = '%b %d', date_syntax = 'due', + recur_syntax = 'rec', + someday_date = '9999-12-30', category_order = {}, gcal = { calendar = 'Tasks', @@ -278,6 +361,15 @@ Fields: ~ this to use a different keyword, for example `'by'` to write `by:2026-03-15` instead of `due:2026-03-15`. + {recur_syntax} (string, default: 'rec') + The token name for inline recurrence metadata. Change + this to use a different keyword, for example + `'repeat'` to write `repeat:weekly`. + + {someday_date} (string, default: '9999-12-30') + The date that `later` and `someday` resolve to. This + acts as a "no date" sentinel for GTD-style workflows. + {category_order} (string[], default: {}) Ordered list of category names. In category view, categories that appear in this list are shown in the @@ -371,6 +463,11 @@ PendingDone Applied to the text of completed tasks. PendingPriority Applied to the `! ` priority marker on priority tasks. Default: links to `DiagnosticWarn`. + *PendingRecur* +PendingRecur Applied to the recurrence indicator virtual text shown + alongside due dates for recurring tasks. + Default: links to `DiagnosticInfo`. + To override a group in your colorscheme or config: >lua vim.api.nvim_set_hl(0, 'PendingDue', { fg = '#aaaaaa', italic = true }) < @@ -388,6 +485,7 @@ Checks performed: ~ category, date format, date syntax) - Whether the data directory exists (warning if not yet created) - Whether the data file exists and can be parsed; reports total task count +- Validates recurrence specs on stored tasks - Whether `curl` is available (required for Google Calendar sync) - Whether `openssl` is available (required for OAuth PKCE) @@ -414,6 +512,8 @@ Task fields: ~ {category} (string) Category name. Defaults to `default_category`. {priority} (integer) `1` for priority tasks, `0` otherwise. {due} (string) ISO date string `YYYY-MM-DD`, or absent. + {recur} (string) Recurrence shorthand (e.g. `weekly`), or absent. + {recur_mode} (string) `'scheduled'` or `'completion'`, or absent. {entry} (string) ISO 8601 UTC timestamp of creation. {modified} (string) ISO 8601 UTC timestamp of last modification. {end} (string) ISO 8601 UTC timestamp of completion or deletion. diff --git a/lua/pending/health.lua b/lua/pending/health.lua index 8a12da4..c37c4f8 100644 --- a/lua/pending/health.lua +++ b/lua/pending/health.lua @@ -27,6 +27,19 @@ function M.check() if load_ok then local tasks = store.tasks() vim.health.ok('Data file loaded: ' .. #tasks .. ' tasks') + local recur = require('pending.recur') + local invalid_count = 0 + for _, task in ipairs(tasks) do + if task.recur and not recur.validate(task.recur) then + invalid_count = invalid_count + 1 + vim.health.warn( + 'Task ' .. task.id .. ' has invalid recurrence spec: ' .. task.recur + ) + end + end + if invalid_count == 0 then + vim.health.ok('All recurrence specs are valid') + end else vim.health.error('Failed to load data file: ' .. tostring(err)) end