setup_env/dotfiles/README.md
Paul Trowbridge fcf1132a61 add td week subcommand, nvim centralization, and README
td week parses git log for task create/complete events and joins with
time.csv for weekly "what got done" reports. Nvim integration moved into
dotfiles/nvim/ (symlinked in by new deploy_nvim step) so all three td
surfaces live under dotfiles. README covers the deploy pattern and td.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 17:25:06 -04:00

95 lines
4.9 KiB
Markdown

# dotfiles
Symlink-deployed config. The parent `~/setup_env/setup_env.sh` installs each file here to its destination path — edit the file in this repo, the change goes live.
| Source in this repo | Deployed to | Deployed by |
| --- | --- | --- |
| `.bashrc`, `.vimrc`, `.gitconfig`, `.pspgconf`, `.psqlrc`, `.tmux.conf`, `.bashrc_local` | `~/<filename>` | `deploy_configs` |
| `bin/*` | `~/.local/bin/<name>` | `deploy_bin` |
| `nvim/*.lua` | `~/.config/nvim/lua/<name>.lua` | `deploy_nvim` |
On a fresh machine: clone the `setup_env` repo, then from `~/setup_env/` run:
```bash
./install_neovim.sh
./install_nvchad.sh
./install_python3.sh
./setup_env.sh # creates all the symlinks + installs apt packages
```
After install you still need to add one line to the NvChad-provided `~/.config/nvim/lua/mappings.lua` (it's not tracked here because NvChad owns that file):
```lua
require("td_mappings")
```
Everything else picks up automatically.
---
## td — markdown todo time tracking
Track time on markdown todos identified by an Obsidian block-ref `^tid-*` at the end of the task line. Data lives in `time.csv` at the vault root; reports cross-join time with git history to show what was created vs. completed.
### The three surfaces (one script)
All logic is in `bin/td` — a Python 3 stdlib script. The other surfaces are thin wrappers so the script is reachable from each editing context.
| Surface | Location | Purpose |
| --- | --- | --- |
| Python script | `bin/td``~/.local/bin/td` | Single source of truth. All subcommands. |
| Shell wrappers | `.bashrc` (`tstart` / `tstop` / `treport` / `tweek`) | Bypass the `td` alias (see gotcha). |
| Nvim module | `nvim/td.lua` + `nvim/td_mappings.lua` | `:TdStart` / `:TdStop` / `:TdReport` / `:TdWeek` commands + `<leader>t{s,p,r,w}` keymaps. |
### Data model
`time.csv` at the vault root:
```
started_at, stopped_at, tid, file, description
```
- `tid` — block-ref identifier, format `tid-YYYYMMDD-HHMMSS`, appended as `^tid-...` to the task line in the markdown file
- `started_at` / `stopped_at` — ISO-8601 local timestamps; a running entry has an empty `stopped_at`
- one row per time segment; `td stop` fills in `stopped_at` on the open row
Vault root is discovered by walking up from the current buffer file looking for `time.csv` or `.obsidian/`.
### Subcommands
| Command | What it does |
| --- | --- |
| `td start <tid> [--file PATH] [--desc TEXT]` | Start a timer. Auto-stops any running entry first. If `--file` / `--desc` aren't given, greps the vault for the tid to populate them. |
| `td stop` | Close the open entry. |
| `td report [FILTER]` | Total time per tid (filter matches tid or file substring). |
| `td current` | Print the currently-running tid (or nothing). |
| `td tidgen` | Print a fresh `tid-YYYYMMDD-HHMMSS`. |
| `td week [--since DATE]` | Task create/complete events from `git log -p`, joined with `time.csv`. Default range: since Monday 00:00 of this week. |
### How `td week` works
Scans `git log -p --reverse --no-renames` from cwd, pairs `-`/`+` task-line diffs within each commit by tid, classifies each event:
- `[x]` **done**`- [ ]``- [x]` transition in one commit
- `[ ]` **new** — added `- [ ]` line with a fresh tid
- `[+]` **done+new**`- [x]` added with no prior `- [ ]` for that tid (created and completed in the same commit)
- `[o]` **reopen**`- [x]``- [ ]` transition
Event timestamp is commit time, not toggle time — batched commits share one timestamp. Fine for weekly "what did I get done" reports; not precise enough for hourly auditing.
### Nvim integration
`<leader>ts` / `:TdStart` on a `- [ ]` task line:
1. If the line has no `^tid-*` block ref, auto-generates `tid-YYYYMMDD-HHMMSS`, appends it, saves the buffer.
2. Starts the timer with the file path (relative to vault root) and the task text (minus checkbox + block ref) as description.
Other mappings: `<leader>tp` stop, `<leader>tr` report float, `<leader>tw` week float. `q` or `<Esc>` closes a float.
Known limitation: NvChad defers `mappings.lua` via `vim.schedule`, so `:TdStart` etc. aren't available inside `-c` arguments on headless invocations. Interactive use is fine.
### Gotchas
- **`td` alone is aliased to `rg`** (for the `td` / `tdp` / `tdo` todo-grep family, defined in `.bashrc`). So `td week` runs `rg "\- \[[^(x|~)]\]" week` and errors out. Use `tweek` (shell wrapper that calls `command td week`) or `command td week` directly.
- **CSV is cwd-scoped.** `$TD_LOG` defaults to `./time.csv`, so subcommands must be run from (or under) the vault root. The nvim wrapper handles this by walking up to find the vault root; the shell wrappers trust your cwd.
- **Data-model changes go in `bin/td`.** The shell and nvim surfaces should stay thin — if a new subcommand is useful in nvim too, add it to `bin/td`, then a one-line `tfoo()` wrapper in `.bashrc` and a `M.foo` + mapping in `nvim/td.lua` / `nvim/td_mappings.lua`.