# pending.nvim Edit tasks like text. `:w` saves them. A buffer-centric task manager for Neovim. Tasks live in a plain buffer — add with `o`, delete with `dd`, reorder with `dd`/`p`, rename by editing. Write the buffer and the diff is computed against a JSON store. No UI chrome, no floating windows, no abstractions between you and your tasks. ## How it works ``` School ! Read chapter 5 Feb 28 Submit homework Feb 25 Errands Buy groceries Mar 01 Clean apartment ``` Category headers sit at column 0. Tasks are indented below them. `!` marks priority. Due dates appear as right-aligned virtual text. Done tasks get strikethrough. Everything you see is editable buffer text — the IDs are concealed, and metadata is parsed from inline syntax on save. ## Install ``` luarocks install pending.nvim ``` **lazy.nvim:** ```lua { 'barrettruth/pending.nvim' } ``` Requires Neovim 0.10+. No external dependencies for local use. Google Calendar sync requires `curl` and `openssl`. ## Usage `:Pending` opens the task buffer. From there, it's just vim: | Key | Action | | --------- | ------------------------------- | | `o` / `O` | Add a new task | | `dd` | Delete a task (on `:w`) | | `p` | Paste (duplicates get new IDs) | | `:w` | Save all changes | | `` | Toggle complete (immediate) | | `` | Switch category / priority view | | `g?` | Show keybind help | ### Inline metadata Type metadata tokens at the end of a task line before saving: ``` Buy milk due:2026-03-15 cat:Errands ``` On `:w`, the date and category are extracted. The description becomes `Buy milk`, the due date renders as virtual text, and the task moves under the `Errands` header. ### Quick add ```vim :Pending add Buy groceries due:2026-03-15 :Pending add School: Submit homework ``` ### Archive ```vim :Pending archive " purge done tasks older than 30 days :Pending archive 7 " purge done tasks older than 7 days ``` ## Configuration No `setup()` call required. Set `vim.g.pending` before the plugin loads: ```lua vim.g.pending = { data_path = vim.fn.stdpath('data') .. '/pending/tasks.json', default_view = 'category', -- 'category' or 'priority' default_category = 'Inbox', date_format = '%b %d', -- strftime format for virtual text date_syntax = 'due', -- inline token name (e.g. 'by' for by:2026-03-15) } ``` All fields are optional. Absent keys use the defaults shown above. ## Google Calendar sync One-way push of tasks with due dates to a dedicated Google Calendar as all-day events. ```lua vim.g.pending = { gcal = { calendar = 'Tasks', credentials_path = '/path/to/client_secret.json', }, } ``` ```vim :Pending sync ``` On first run, a browser window opens for OAuth consent. The refresh token is stored at `stdpath('data')/pending/gcal_tokens.json`. Completed or deleted tasks have their calendar events removed. Due date changes update events in place. ## Mappings The plugin defines `` mappings for custom keybinds: ```lua vim.keymap.set('n', 't', '(pending-open)') vim.keymap.set('n', 'T', '(pending-toggle)') ``` | Plug mapping | Action | | -------------------------- | -------------------- | | `(pending-open)` | Open task buffer | | `(pending-toggle)` | Toggle complete | | `(pending-view)` | Switch view | | `(pending-priority)` | Toggle priority flag | | `(pending-date)` | Prompt for due date | ## Data format Tasks are stored as JSON at `stdpath('data')/pending/tasks.json`. The schema is versioned and forward-compatible — unknown fields are preserved on round-trip. ## Documentation ```vim :checkhealth pending ```