pending.nvim/README.md
Barrett Ruth 47a5c7a5e5 docs: add README
Problem: repo had no documentation for users.

Solution: add README covering usage, configuration, inline
metadata syntax, Google Calendar sync, mappings, and data
format.
2026-02-24 15:20:18 -05:00

3.8 KiB

todo.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 todo.nvim

lazy.nvim:

{ 'barrettruth/todo.nvim' }

Requires Neovim 0.10+. No external dependencies for local use. Google Calendar sync requires curl and openssl.

Usage

:Todo 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
<CR> Toggle complete (immediate)
<Tab> 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

:Todo add Buy groceries due:2026-03-15
:Todo add School: Submit homework

Archive

:Todo archive      " purge done tasks older than 30 days
:Todo archive 7    " purge done tasks older than 7 days

Configuration

No setup() call required. Set vim.g.todo before the plugin loads:

vim.g.todo = {
  data_path = vim.fn.stdpath('data') .. '/todo/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.

vim.g.todo = {
  gcal = {
    calendar = 'Tasks',
    credentials_path = '/path/to/client_secret.json',
  },
}
:Todo sync

On first run, a browser window opens for OAuth consent. The refresh token is stored at stdpath('data')/todo/gcal_tokens.json. Completed or deleted tasks have their calendar events removed. Due date changes update events in place.

Mappings

The plugin defines <Plug> mappings for custom keybinds:

vim.keymap.set('n', '<leader>t', '<Plug>(todo-open)')
vim.keymap.set('n', '<leader>T', '<Plug>(todo-toggle)')
Plug mapping Action
<Plug>(todo-open) Open task buffer
<Plug>(todo-toggle) Toggle complete
<Plug>(todo-view) Switch view
<Plug>(todo-priority) Toggle priority flag
<Plug>(todo-date) Prompt for due date

Data format

Tasks are stored as JSON at stdpath('data')/todo/tasks.json. The schema is versioned and forward-compatible — unknown fields are preserved on round-trip.

Documentation

:checkhealth todo