Google Tasks sync + shared OAuth module (#60)
* feat(gtasks): add Google Tasks bidirectional sync
Problem: pending.nvim only supported one-way push to Google Calendar.
Users who use Google Tasks had no way to sync tasks bidirectionally.
Solution: add `lua/pending/sync/gtasks.lua` backend with OAuth PKCE
auth, push/pull/sync actions, and field mapping between pending tasks
and Google Tasks (category↔tasklist, `priority`/`recur` via notes).
* refactor(cli): promote sync backends to top-level subcommands
Problem: `:Pending sync gtasks auth` required an extra `sync` keyword
that added no value and made the command unnecessarily verbose.
Solution: route `gtasks` and `gcal` as top-level `:Pending` subcommands
via `SYNC_BACKEND_SET` lookup. Tab completion introspects backend
modules for available actions instead of hardcoding `{ 'auth', 'sync' }`.
* 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.
* ci: format
* refactor(sync): extract shared OAuth into `oauth.lua`
Problem: `gcal.lua` and `gtasks.lua` duplicated ~250 lines of identical
OAuth code (token management, PKCE flow, credential loading, curl
helpers, url encoding).
Solution: Extract a shared `OAuthClient` metatable in `oauth.lua` with
module-level utilities and instance methods. Both backends now delegate
all OAuth to `oauth.new()`. Skip `oauth` in `health.lua` backend
discovery by checking for a `name` field.
* feat(sync): ship bundled OAuth credentials
Problem: Users must manually create a Google Cloud project and place a
credentials JSON file before sync works — terrible onboarding.
Solution: Add `client_id`/`client_secret` fields to `GcalConfig` and
`GtasksConfig`. `oauth.lua` resolves credentials in three tiers: config
fields, credentials file, then bundled defaults (placeholders for now).
* docs(sync): document bundled credentials and config fields
* ci: format
This commit is contained in:
parent
21628abe53
commit
e0e3af6787
7 changed files with 726 additions and 743 deletions
|
|
@ -608,11 +608,8 @@ loads: >lua
|
|||
sync = {
|
||||
gcal = {
|
||||
calendar = 'Pendings',
|
||||
credentials_path = '/path/to/client_secret.json',
|
||||
},
|
||||
gtasks = {
|
||||
credentials_path = '/path/to/client_secret.json',
|
||||
},
|
||||
gtasks = {},
|
||||
},
|
||||
}
|
||||
<
|
||||
|
|
@ -683,7 +680,9 @@ Fields: ~
|
|||
{sync} (table, default: {}) *pending.SyncConfig*
|
||||
Sync backend configuration. Each key is a backend
|
||||
name and the value is the backend-specific config
|
||||
table. Currently only `gcal` is built-in.
|
||||
table. Built-in backends: `gcal`, `gtasks`. Both
|
||||
ship bundled OAuth credentials so no setup is
|
||||
needed beyond `:Pending <backend> auth`.
|
||||
|
||||
{icons} (table) *pending.Icons*
|
||||
Icon characters displayed in the buffer. The
|
||||
|
|
@ -934,12 +933,14 @@ Configuration: >lua
|
|||
sync = {
|
||||
gcal = {
|
||||
calendar = 'Pendings',
|
||||
credentials_path = '/path/to/client_secret.json',
|
||||
},
|
||||
},
|
||||
}
|
||||
<
|
||||
|
||||
No configuration is required to get started — bundled OAuth credentials are
|
||||
used by default. Run `:Pending gcal auth` and the browser opens immediately.
|
||||
|
||||
*pending.GcalConfig*
|
||||
Fields: ~
|
||||
{calendar} (string, default: 'Pendings')
|
||||
|
|
@ -947,13 +948,27 @@ Fields: ~
|
|||
with this name does not exist it is created
|
||||
automatically on the first sync.
|
||||
|
||||
{credentials_path} (string)
|
||||
Path to the OAuth client secret JSON file downloaded
|
||||
{client_id} (string, optional)
|
||||
OAuth client ID. When set together with
|
||||
{client_secret}, these take priority over the
|
||||
credentials file and bundled defaults.
|
||||
|
||||
{client_secret} (string, optional)
|
||||
OAuth client secret. See {client_id}.
|
||||
|
||||
{credentials_path} (string, optional)
|
||||
Path to an OAuth client secret JSON file downloaded
|
||||
from the Google Cloud Console. Default:
|
||||
`stdpath('data')..'/pending/gcal_credentials.json'`.
|
||||
The file may be in the `installed` wrapper format
|
||||
that Google provides or as a bare credentials object.
|
||||
|
||||
Credential resolution: ~
|
||||
Credentials are resolved in order:
|
||||
1. `client_id` + `client_secret` config fields (highest priority).
|
||||
2. JSON file at `credentials_path` (or the default path).
|
||||
3. Bundled credentials shipped with the plugin (always available).
|
||||
|
||||
OAuth flow: ~
|
||||
On the first `:Pending gcal` call the plugin detects that no refresh token
|
||||
exists and opens the Google authorization URL in the browser using
|
||||
|
|
@ -988,22 +1003,34 @@ created automatically on first sync.
|
|||
Configuration: >lua
|
||||
vim.g.pending = {
|
||||
sync = {
|
||||
gtasks = {
|
||||
credentials_path = '/path/to/client_secret.json',
|
||||
},
|
||||
gtasks = {},
|
||||
},
|
||||
}
|
||||
<
|
||||
|
||||
No configuration is required to get started — bundled OAuth credentials are
|
||||
used by default. Run `:Pending gtasks auth` and the browser opens immediately.
|
||||
|
||||
*pending.GtasksConfig*
|
||||
Fields: ~
|
||||
{credentials_path} (string)
|
||||
Path to the OAuth client secret JSON file downloaded
|
||||
{client_id} (string, optional)
|
||||
OAuth client ID. When set together with
|
||||
{client_secret}, these take priority over the
|
||||
credentials file and bundled defaults.
|
||||
|
||||
{client_secret} (string, optional)
|
||||
OAuth client secret. See {client_id}.
|
||||
|
||||
{credentials_path} (string, optional)
|
||||
Path to an 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.
|
||||
|
||||
Credential resolution: ~
|
||||
Same three-tier resolution as the gcal backend (see |pending-gcal|).
|
||||
|
||||
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`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue