From 2b87337d78cfffca60abd74dfaf1d1836a7faacc Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Thu, 26 Feb 2026 23:09:05 -0500 Subject: [PATCH] docs(pending): reorganize vimdoc and fix incorrect defaults (#52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(config): remove legacy gcal top-level config key Problem: the gcal migration shim silently accepted vim.g.pending = { gcal = {...} } and copied it to sync.gcal, adding complexity and a deprecated API surface. Solution: remove the migration block in config.get(), drop the cfg.gcal fallback in gcal_config(), delete the two migration tests, and clean up the vimdoc references. Callers must now use sync.gcal directly. * ci: fix * fix(spec): remove duplicate buffer require in complete_spec * docs(pending): reorganize vimdoc and fix incorrect defaults Problem: sections were out of logical order — inline metadata appeared before commands, GCal before its own backend framework, store resolution duplicated and buried after health check. Two defaults were wrong: default_category documented as 'Inbox' (should be 'Todo') and the gcal calendar example used 'Tasks' (should be 'Pendings'). Solution: reorder all 21 sections into onboarding-first flow, add a CONTENTS table with hyperlinks, fix both incorrect defaults in every location they appeared, and remove the duplicate STORE RESOLUTION section. --- doc/pending.txt | 496 ++++++++++++++++++++++++------------------------ 1 file changed, 250 insertions(+), 246 deletions(-) diff --git a/doc/pending.txt b/doc/pending.txt index 3577f49..56a87d5 100644 --- a/doc/pending.txt +++ b/doc/pending.txt @@ -42,6 +42,30 @@ Features: ~ - Omnifunc completion for `cat:`, `due:`, and `rec:` tokens (``) - Google Calendar one-way push via OAuth PKCE +============================================================================== +CONTENTS *pending-contents* + + 1. Introduction ............................................. |pending.nvim| + 2. Requirements ..................................... |pending-requirements| + 3. Install ............................................... |pending-install| + 4. Usage ................................................... |pending-usage| + 5. Commands .............................................. |pending-commands| + 6. Mappings .............................................. |pending-mappings| + 7. Views ................................................... |pending-views| + 8. Filters ............................................... |pending-filters| + 9. Inline Metadata ....................................... |pending-metadata| + 10. Date Input .............................................. |pending-dates| + 11. Recurrence ......................................... |pending-recurrence| + 12. Configuration ........................................... |pending-config| + 13. Store Resolution .......................... |pending-store-resolution| + 14. Highlight Groups .................................... |pending-highlights| + 15. Lua API ................................................... |pending-api| + 16. Recipes ............................................... |pending-recipes| + 17. Sync Backends ................................... |pending-sync-backend| + 18. Google Calendar .......................................... |pending-gcal| + 19. Data Format .............................................. |pending-data| + 20. Health Check ........................................... |pending-health| + ============================================================================== REQUIREMENTS *pending-requirements* @@ -89,134 +113,6 @@ persists across window switches; reopening with `:Pending` focuses the existing window if one is open. The buffer is automatically reloaded from disk when entered unmodified. -============================================================================== -INLINE METADATA *pending-metadata* - -Metadata tokens may be appended to any task line before saving. Tokens are -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:` 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|. 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 -`2026-03-15` and rendered as right-aligned virtual text, and the task is -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:`, one -`cat:`, and one `rec:` per task line are consumed. - -Omnifunc completion is available for `due:`, `cat:`, and `rec:` token types. -In insert mode, type the token prefix 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`) - -Time suffix: ~ *pending-dates-time* -Any named date or absolute date accepts an `@` time suffix. Supported -formats: `HH:MM` (24h), `H:MM`, bare hour (`9`, `14`), and am/pm -(`2pm`, `9:30am`, `12am`). All forms are normalized to `HH:MM` on save. > - - due:tomorrow@2pm " tomorrow at 14:00 - due:fri@9 " next Friday at 09:00 - due:+1w@17:00 " one week from today at 17:00 - due:tomorrow@9:30am " tomorrow at 09:30 - due:2026-03-15@08:00 " absolute date with time - due:2026-03-15T14:30 " ISO 8601 datetime (also accepted) -< - -Tasks with a time component are not considered overdue until after the -specified time. The time is displayed alongside the date in virtual text -and preserved across recurrence advances. - -============================================================================== -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* @@ -522,6 +418,134 @@ predicates. Deleting the `FILTER:` line and saving clears the filter. The line is highlighted with |PendingFilter| and does not appear in the stored task data. +============================================================================== +INLINE METADATA *pending-metadata* + +Metadata tokens may be appended to any task line before saving. Tokens are +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:` 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|. 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 +`2026-03-15` and rendered as right-aligned virtual text, and the task is +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:`, one +`cat:`, and one `rec:` per task line are consumed. + +Omnifunc completion is available for `due:`, `cat:`, and `rec:` token types. +In insert mode, type the token prefix 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`) + +Time suffix: ~ *pending-dates-time* +Any named date or absolute date accepts an `@` time suffix. Supported +formats: `HH:MM` (24h), `H:MM`, bare hour (`9`, `14`), and am/pm +(`2pm`, `9:30am`, `12am`). All forms are normalized to `HH:MM` on save. > + + due:tomorrow@2pm " tomorrow at 14:00 + due:fri@9 " next Friday at 09:00 + due:+1w@17:00 " one week from today at 17:00 + due:tomorrow@9:30am " tomorrow at 09:30 + due:2026-03-15@08:00 " absolute date with time + due:2026-03-15T14:30 " ISO 8601 datetime (also accepted) +< + +Tasks with a time component are not considered overdue until after the +specified time. The time is displayed alongside the date in virtual text +and preserved across recurrence advances. + +============================================================================== +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). + ============================================================================== CONFIGURATION *pending-config* @@ -530,7 +554,7 @@ loads: >lua vim.g.pending = { data_path = vim.fn.stdpath('data') .. '/pending/tasks.json', default_view = 'category', - default_category = 'Inbox', + default_category = 'Todo', date_format = '%b %d', date_syntax = 'due', recur_syntax = 'rec', @@ -556,7 +580,7 @@ loads: >lua }, sync = { gcal = { - calendar = 'Tasks', + calendar = 'Pendings', credentials_path = '/path/to/client_secret.json', }, }, @@ -578,7 +602,7 @@ Fields: ~ The view to use when the buffer is opened for the first time in a session. - {default_category} (string, default: 'Inbox') + {default_category} (string, default: 'Todo') Category assigned to new tasks when no `cat:` token is present and no `Category: ` prefix is used with `:Pending add`. @@ -641,6 +665,68 @@ Fields: ~ {recur} Recurrence prefix. Default: '↺' {category} Category label prefix. Default: '#' +============================================================================== +STORE RESOLUTION *pending-store-resolution* + +When pending.nvim opens the task buffer it resolves which store file to use: + +1. Search upward from `vim.fn.getcwd()` for a file named `.pending.json`. +2. If found, use that file as the active store (project-local store). +3. If not found, fall back to `data_path` from |pending-config| (global + store). + +This means placing a `.pending.json` file in a project root makes that +project use an isolated task list. Tasks in the project store are completely +separate from tasks in the global store; there is no aggregation. + +To create a project-local store in the current directory: >vim + :Pending init +< + +The `:checkhealth pending` report shows which store file is currently active. + +============================================================================== +HIGHLIGHT GROUPS *pending-highlights* + +pending.nvim defines the following highlight groups. All groups are set with +`default`, so colorschemes can override them by defining the group without +`default` before or after the plugin loads. + + *PendingHeader* +PendingHeader Applied to category header lines (text at column 0). + Default: links to `Title`. + + *PendingDue* +PendingDue Applied to the due date virtual text shown at the right + margin of each task line. + Default: links to `DiagnosticHint`. + + *PendingOverdue* +PendingOverdue Applied to the due date virtual text of overdue tasks. + Default: links to `DiagnosticError`. + + *PendingDone* +PendingDone Applied to the text of completed tasks. + Default: links to `Comment`. + + *PendingPriority* +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`. + + *PendingFilter* +PendingFilter Applied to the `FILTER:` header line shown at the top of + the buffer when a filter is active. + Default: links to `DiagnosticWarn`. + +To override a group in your colorscheme or config: >lua + vim.api.nvim_set_hl(0, 'PendingDue', { fg = '#aaaaaa', italic = true }) +< + ============================================================================== LUA API *pending-api* @@ -857,6 +943,31 @@ Open tasks in a new tab on startup: >lua end, }) < + +============================================================================== +SYNC BACKENDS *pending-sync-backend* + +Sync backends are Lua modules under `lua/pending/sync/.lua`. Each +module returns a table conforming to the backend interface: >lua + + ---@class pending.SyncBackend + ---@field name string + ---@field auth fun(): nil + ---@field sync fun(): nil + ---@field health? fun(): nil +< + +Required fields: ~ + {name} Backend identifier (matches the filename). + {sync} Main sync action. Called by `:Pending sync `. + {auth} Authorization flow. Called by `:Pending sync auth`. + +Optional fields: ~ + {health} Called by `:checkhealth pending` to report backend-specific + diagnostics (e.g. checking for external tools). + +Backend-specific configuration goes under `sync.` in |pending-config|. + ============================================================================== GOOGLE CALENDAR *pending-gcal* @@ -868,7 +979,7 @@ Configuration: >lua vim.g.pending = { sync = { gcal = { - calendar = 'Tasks', + calendar = 'Pendings', credentials_path = '/path/to/client_secret.json', }, }, @@ -913,119 +1024,6 @@ For each task in the store: A summary notification is shown after sync: `created: N, updated: N, deleted: N`. -============================================================================== -SYNC BACKENDS *pending-sync-backend* - -Sync backends are Lua modules under `lua/pending/sync/.lua`. Each -module returns a table conforming to the backend interface: >lua - - ---@class pending.SyncBackend - ---@field name string - ---@field auth fun(): nil - ---@field sync fun(): nil - ---@field health? fun(): nil -< - -Required fields: ~ - {name} Backend identifier (matches the filename). - {sync} Main sync action. Called by `:Pending sync `. - {auth} Authorization flow. Called by `:Pending sync auth`. - -Optional fields: ~ - {health} Called by `:checkhealth pending` to report backend-specific - diagnostics (e.g. checking for external tools). - -Backend-specific configuration goes under `sync.` in |pending-config|. - -============================================================================== -HIGHLIGHT GROUPS *pending-highlights* - -pending.nvim defines the following highlight groups. All groups are set with -`default`, so colorschemes can override them by defining the group without -`default` before or after the plugin loads. - - *PendingHeader* -PendingHeader Applied to category header lines (text at column 0). - Default: links to `Title`. - - *PendingDue* -PendingDue Applied to the due date virtual text shown at the right - margin of each task line. - Default: links to `DiagnosticHint`. - - *PendingOverdue* -PendingOverdue Applied to the due date virtual text of overdue tasks. - Default: links to `DiagnosticError`. - - *PendingDone* -PendingDone Applied to the text of completed tasks. - Default: links to `Comment`. - - *PendingPriority* -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`. - - *PendingFilter* -PendingFilter Applied to the `FILTER:` header line shown at the top of - the buffer when a filter is active. - Default: links to `DiagnosticWarn`. - -To override a group in your colorscheme or config: >lua - vim.api.nvim_set_hl(0, 'PendingDue', { fg = '#aaaaaa', italic = true }) -< - -============================================================================== -HEALTH CHECK *pending-health* - -Run |:checkhealth| pending to verify your setup: >vim - :checkhealth pending -< - -============================================================================== -STORE RESOLUTION *pending-store-resolution* - -When pending.nvim opens the task buffer it resolves which store file to use: - -1. Search upward from `vim.fn.getcwd()` for a file named `.pending.json`. -2. If found, use that file as the active store (project-local store). -3. If not found, fall back to `data_path` from |pending-config| (global - store). - -This means placing a `.pending.json` file in a project root makes that -project use an isolated task list. Tasks in the project store are completely -separate from tasks in the global store; there is no aggregation. - -To create a project-local store in the current directory: >vim - :Pending init -< - -The `:checkhealth pending` report shows which store file is currently active. - -============================================================================== -STORE RESOLUTION *pending-store-resolution* - -When pending.nvim opens the task buffer it resolves which store file to use: - -1. Search upward from `vim.fn.getcwd()` for a file named `.pending.json`. -2. If found, use that file as the active store (project-local store). -3. If not found, fall back to `data_path` from |pending-config| (global - store). - -This means placing a `.pending.json` file in a project root makes that -project use an isolated task list. Tasks in the project store are completely -separate from tasks in the global store; there is no aggregation. - -To create a project-local store in the current directory: >vim - :Pending init -< - -The `:checkhealth pending` report shows which store file is currently active. - ============================================================================== DATA FORMAT *pending-data* @@ -1067,4 +1065,10 @@ version the plugin supports, loading is aborted with an error message asking you to update the plugin. ============================================================================== - vim:tw=78:ts=8:ft=help:norl: +HEALTH CHECK *pending-health* + +Run |:checkhealth| pending to verify your setup: >vim + :checkhealth pending +< + +==============================================================================