# 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` | `~/` | `deploy_configs` | | `bin/*` | `~/.local/bin/` | `deploy_bin` | | `nvim/*.lua` | `~/.config/nvim/lua/.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 + `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 [--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 `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: `tp` stop, `tr` report float, `tw` week float. `q` or `` 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`.