docs(gtasks): document Google Tasks backend and CLI changes

Problem: vimdoc had no coverage for the gtasks backend and still
referenced the old `:Pending sync <backend>` command form.

Solution: add `:Pending-gtasks` and `:Pending-gcal` command sections
with per-action docs, update sync backend interface, and add gtasks
config example.
This commit is contained in:
Barrett Ruth 2026-03-05 00:59:08 -05:00
parent ffc588ccf9
commit e8894d7d8b

View file

@ -41,6 +41,7 @@ Features: ~
- Foldable category sections (`zc`/`zo`) in category view - Foldable category sections (`zc`/`zo`) in category view
- Omnifunc completion for `cat:`, `due:`, and `rec:` tokens (`<C-x><C-o>`) - Omnifunc completion for `cat:`, `due:`, and `rec:` tokens (`<C-x><C-o>`)
- Google Calendar one-way push via OAuth PKCE - Google Calendar one-way push via OAuth PKCE
- Google Tasks bidirectional sync via OAuth PKCE
============================================================================== ==============================================================================
CONTENTS *pending-contents* CONTENTS *pending-contents*
@ -63,15 +64,16 @@ CONTENTS *pending-contents*
16. Recipes ............................................... |pending-recipes| 16. Recipes ............................................... |pending-recipes|
17. Sync Backends ................................... |pending-sync-backend| 17. Sync Backends ................................... |pending-sync-backend|
18. Google Calendar .......................................... |pending-gcal| 18. Google Calendar .......................................... |pending-gcal|
19. Data Format .............................................. |pending-data| 19. Google Tasks ............................................ |pending-gtasks|
20. Health Check ........................................... |pending-health| 20. Data Format .............................................. |pending-data|
21. Health Check ........................................... |pending-health|
============================================================================== ==============================================================================
REQUIREMENTS *pending-requirements* REQUIREMENTS *pending-requirements*
- Neovim 0.10+ - Neovim 0.10+
- No external dependencies for local use - No external dependencies for local use
- `curl` and `openssl` are required for the `gcal` sync backend - `curl` and `openssl` are required for the `gcal` and `gtasks` sync backends
============================================================================== ==============================================================================
INSTALL *pending-install* INSTALL *pending-install*
@ -146,24 +148,42 @@ COMMANDS *pending-commands*
Populate the quickfix list with all tasks that are overdue or due today. Populate the quickfix list with all tasks that are overdue or due today.
Open the list with |:copen| to navigate to each task's category. Open the list with |:copen| to navigate to each task's category.
*:Pending-sync* *:Pending-gtasks*
:Pending sync {backend} [{action}] :Pending gtasks [{action}]
Run a sync action against a named backend. {backend} is required — bare Run a Google Tasks sync action. {action} defaults to `sync` when omitted.
`:Pending sync` prints a usage message. {action} defaults to `sync`
when omitted. Each backend lives at `lua/pending/sync/<name>.lua`. Actions: ~
`sync` Push local changes then pull remote changes (default).
`push` Push local changes to Google Tasks only.
`pull` Pull remote changes from Google Tasks only.
`auth` Run the OAuth authorization flow.
Examples: >vim Examples: >vim
:Pending sync gcal " runs gcal.sync() :Pending gtasks " push then pull (default)
:Pending sync gcal auth " runs gcal.auth() :Pending gtasks push " push local → Google Tasks
:Pending sync gcal sync " explicit sync (same as bare) :Pending gtasks pull " pull Google Tasks → local
:Pending gtasks auth " authorize
< <
Tab completion after `:Pending sync ` lists discovered backends. Tab completion after `:Pending gtasks ` lists available actions.
Tab completion after `:Pending sync gcal ` lists available actions. See |pending-gtasks| for full details.
Built-in backends: ~ *:Pending-gcal*
:Pending gcal [{action}]
Run a Google Calendar sync action. {action} defaults to `sync` when
omitted.
`gcal` Google Calendar one-way push. See |pending-gcal|. Actions: ~
`sync` Push tasks with due dates to Google Calendar (default).
`auth` Run the OAuth authorization flow.
Examples: >vim
:Pending gcal " push to Google Calendar (default)
:Pending gcal auth " authorize
<
Tab completion after `:Pending gcal ` lists available actions.
See |pending-gcal| for full details.
*:Pending-filter* *:Pending-filter*
:Pending filter {predicates} :Pending filter {predicates}
@ -590,6 +610,9 @@ loads: >lua
calendar = 'Pendings', calendar = 'Pendings',
credentials_path = '/path/to/client_secret.json', credentials_path = '/path/to/client_secret.json',
}, },
gtasks = {
credentials_path = '/path/to/client_secret.json',
},
}, },
} }
< <
@ -870,21 +893,30 @@ Open tasks in a new tab on startup: >lua
SYNC BACKENDS *pending-sync-backend* SYNC BACKENDS *pending-sync-backend*
Sync backends are Lua modules under `lua/pending/sync/<name>.lua`. Each Sync backends are Lua modules under `lua/pending/sync/<name>.lua`. Each
module returns a table conforming to the backend interface: >lua backend is exposed as a top-level `:Pending` subcommand: >vim
:Pending gtasks [action]
:Pending gcal [action]
<
Each module returns a table conforming to the backend interface: >lua
---@class pending.SyncBackend ---@class pending.SyncBackend
---@field name string ---@field name string
---@field auth fun(): nil ---@field auth fun(): nil
---@field sync fun(): nil ---@field sync fun(): nil
---@field push? fun(): nil
---@field pull? fun(): nil
---@field health? fun(): nil ---@field health? fun(): nil
< <
Required fields: ~ Required fields: ~
{name} Backend identifier (matches the filename). {name} Backend identifier (matches the filename).
{sync} Main sync action. Called by `:Pending sync <name>`. {sync} Main sync action. Called by `:Pending <name>`.
{auth} Authorization flow. Called by `:Pending sync <name> auth`. {auth} Authorization flow. Called by `:Pending <name> auth`.
Optional fields: ~ Optional fields: ~
{push} Push-only action. Called by `:Pending <name> push`.
{pull} Pull-only action. Called by `:Pending <name> pull`.
{health} Called by `:checkhealth pending` to report backend-specific {health} Called by `:checkhealth pending` to report backend-specific
diagnostics (e.g. checking for external tools). diagnostics (e.g. checking for external tools).
@ -923,7 +955,7 @@ Fields: ~
that Google provides or as a bare credentials object. that Google provides or as a bare credentials object.
OAuth flow: ~ OAuth flow: ~
On the first `:Pending sync gcal` call the plugin detects that no refresh token On the first `:Pending gcal` call the plugin detects that no refresh token
exists and opens the Google authorization URL in the browser using exists and opens the Google authorization URL in the browser using
|vim.ui.open()|. A temporary local HTTP server listens on port 18392 for the |vim.ui.open()|. A temporary local HTTP server listens on port 18392 for the
OAuth redirect. The PKCE (Proof Key for Code Exchange) flow is used — OAuth redirect. The PKCE (Proof Key for Code Exchange) flow is used —
@ -933,7 +965,7 @@ authorization code is exchanged for tokens and the refresh token is stored at
use the stored refresh token and refresh the access token automatically when use the stored refresh token and refresh the access token automatically when
it is about to expire. it is about to expire.
`:Pending sync gcal` behavior: ~ `:Pending gcal` behavior: ~
For each task in the store: For each task in the store:
- A pending task with a due date and no existing event: a new all-day event is - A pending task with a due date and no existing event: a new all-day event is
created and the event ID is stored in the task's `_extra` table. created and the event ID is stored in the task's `_extra` table.
@ -946,6 +978,67 @@ For each task in the store:
A summary notification is shown after sync: `created: N, updated: N, A summary notification is shown after sync: `created: N, updated: N,
deleted: N`. deleted: N`.
==============================================================================
GOOGLE TASKS *pending-gtasks*
pending.nvim can sync tasks bidirectionally with Google Tasks. Each
pending.nvim category maps to a Google Tasks list of the same name. Lists are
created automatically on first sync.
Configuration: >lua
vim.g.pending = {
sync = {
gtasks = {
credentials_path = '/path/to/client_secret.json',
},
},
}
<
*pending.GtasksConfig*
Fields: ~
{credentials_path} (string)
Path to the OAuth client secret JSON file downloaded
from the Google Cloud Console. Default:
`stdpath('data')..'/pending/gtasks_credentials.json'`.
Accepts the `installed` wrapper format or a bare
credentials object.
OAuth flow: ~
Same PKCE flow as the gcal backend; listens on port 18393. Tokens are stored
at `stdpath('data')/pending/gtasks_tokens.json`. Run `:Pending gtasks auth`
to authorize; subsequent syncs refresh the token automatically.
`:Pending gtasks` actions: ~
`:Pending gtasks` (or `:Pending gtasks sync`) runs push then pull. Use
`:Pending gtasks push` or `:Pending gtasks pull` to run only one direction.
Push (local → Google Tasks, `:Pending gtasks push`):
- Pending task with no `_gtasks_task_id`: created in the matching list.
- Pending task with an existing ID: updated in Google Tasks.
- Done task with an existing ID: marked `completed` in Google Tasks.
- Deleted task with an existing ID: deleted from Google Tasks.
Pull (Google Tasks → local, `:Pending gtasks pull`):
- GTasks task already known (matched by `_gtasks_task_id`): updated locally
if `gtasks.updated` timestamp is newer than `task.modified`.
- GTasks task not known locally: created as a new pending.nvim task in the
category matching the list name.
Field mapping: ~
{title} ↔ task description
{status} `needsAction` ↔ `pending`, `completed` ↔ `done`
{due} date-only; time component ignored (GTasks limitation)
{notes} serializes extra fields: `pri:1 rec:weekly`
The `notes` field is used exclusively for pending.nvim metadata. Any existing
notes on tasks created outside pending.nvim are parsed for known tokens and
the remainder is ignored.
Recurrence (`rec:`) is stored in notes for round-tripping but is not
expanded by Google Tasks (GTasks has no recurrence API).
============================================================================== ==============================================================================
DATA FORMAT *pending-data* DATA FORMAT *pending-data*
@ -979,7 +1072,8 @@ Task fields: ~
Any field not in the list above is preserved in `_extra` and written back on Any field not in the list above is preserved in `_extra` and written back on
save. This is used internally to store the Google Calendar event ID save. This is used internally to store the Google Calendar event ID
(`_gcal_event_id`) and allows third-party tooling to annotate tasks without (`_gcal_event_id`) and Google Tasks IDs (`_gtasks_task_id`,
`_gtasks_list_id`), and allows third-party tooling to annotate tasks without
data loss. data loss.
The `version` field is checked on load. If the file version is newer than the The `version` field is checked on load. If the file version is newer than the