aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* chore(todo): mark gptel model refresh DONECraig Jennings2026-05-141-7/+30
|
* chore(ai-config): refresh gptel model menusCraig Jennings2026-05-141-8/+7
| | | | | | | | | | | | | | | | | | | Anthropic: bump Opus 4.6 → 4.7 (current frontier). Sonnet 4.6 and Haiku 4.5 stay -- still current. Default `gptel-model' setq also bumped to claude-opus-4-7 in both places it was set. OpenAI: drop the cohort retired from ChatGPT on 2026-02-13 (gpt-4o, gpt-5 original, gpt-4.1, o1). Replace with the current lineup: gpt-5.5 (flagship), gpt-5.4-mini (fast/cheap), o3 (reasoning). All three are documented at developers.openai.com/api/docs/models/. Drive-by: stale docstring example in cj/gptel--current-model-selection bumped to match. gptel's bundled :models list only knows up to May-2025 IDs but gptel-make-anthropic / gptel-make-openai accept any string and pass it straight to the API, so newer names work without a gptel upgrade.
* chore(todo): queue gptel model refresh + C-; b p source extensionsCraig Jennings2026-05-141-9/+18
|
* feat(markdown-config): register markdown as an org src-block languageCraig Jennings2026-05-142-0/+34
| | | | | | | | | | | | | | | | | | | `#+begin_src markdown ... #+end_src' blocks rendered and exported fine but `org-lint' warned on every one of them ("Unknown source block language: 'markdown'"), and `C-c '' inside the block fell back to `fundamental-mode' instead of opening it in `markdown-mode' for editing. Add a `with-eval-after-load 'org' form that pushes `("markdown" . markdown)' onto `org-src-lang-modes'. New ERT test in `tests/test-markdown-config.el' asserts the entry resolves to `markdown' after `(require 'markdown-config)'. Surfaced while clearing `org-lint' on `todo.org' from 55 issues down to 1 -- the last one was this warning on a Linear ticket-body draft that was genuinely markdown. Registering the language is the right fix; relabeling the block as `text' or `example' would lose accuracy.
* chore(todo): archive today's DONE work + sync child prioritiesCraig Jennings2026-05-141-545/+536
| | | | | | | | | | | Five level-2 subtrees moved into the Resolved section: - Surface org narrowing + sparse-tree under C-; O - F9 toggle restores single-window layout (older) - AI-vterm scrollback history replaces agent buffer (older) - Add ERT coverage for modules below 70% - Fix Python tree-sitter font-lock query syntax error Five child priorities bumped to match their parents.
* chore(todo): mark org narrowing + sparse-tree task DONECraig Jennings2026-05-141-1/+14
|
* refactor(org-config): surface narrowing + sparse-tree under C-; OCraig Jennings2026-05-142-5/+62
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Narrowing and sparse-tree commands existed in the `:bind' block on `C-c'-style shortcuts but nothing in `cj/org-map' surfaced them, so which-key never showed them and discoverability was poor. Add direct bindings under `C-; O', flat (no sub-prefixes for narrow / sparse-tree). Lowercase creates; capital of the same letter cancels: - `n' / `N' narrow-to-subtree / widen - `s' / `S' match-sparse-tree / show-all - `t' / `T' show-todo-tree / show-all - `>' / `<' forward / backward sibling narrow (kept as-is) - `R' reveal-context (no lowercase pair -- `r' is the table-row sub-prefix) Both `S' and `T' resolve to the same `org-show-all' command so the mental model is just "capital cancels the lowercase I just ran" without having to recall which letter the cancel actually lives on. Free up F2: the old `(<f2> . org-reveal)' binding in the org-mode `:bind' block is now redundant with `C-; O R'. Drop it; F2 becomes available for whatever wants it next. Four new ERT assertions in `test-org-config-keymap-ownership.el' lock the shape -- the old sparse-tree-submap test was rewritten for the flat layout and the narrow-submap test became narrow-bindings (also flat).
* chore(todo): add task to surface org narrowing + sparse-tree under C-; OCraig Jennings2026-05-141-0/+42
|
* chore(todo): mark dashboard rebalance DONECraig Jennings2026-05-141-1/+14
|
* refactor(dashboard): regroup launcher icons into 4/4/4 by purposeCraig Jennings2026-05-141-33/+39
| | | | | | | | | | | | | | | | | | | | | | Telegram had landed alone on a third row of one icon, with the first two rows holding a mixed bag (Code next to Email next to Agenda next to Files next to Music; Feeds next to IRC next to Slack next to Flashcards next to Books next to Terminal). No category showed up grouped, and the asymmetry was bugging me every dashboard open. Regroup by what the icons actually do. Three rows of four: - Row 1 Work: Code / Files / Terminal / Agenda - Row 2 Read & Learn: Feeds / Books / Flashcards / Music - Row 3 Communication: Email / IRC / Slack / Telegram Reorder the `define-key' calls on `dashboard-mode-map' to mirror the row layout -- reading the keymap top-to-bottom now matches reading the icons left-to-right. Drive-by fix in the same commit: Music had an icon but no `dashboard-mode-map' keybinding (mouse-only). Bound to `m'.
* chore(todo): mark video-T transcription task DONECraig Jennings2026-05-141-1/+2
|
* feat(transcription): extend dired T to transcribe videos via ffmpeg, with testsCraig Jennings2026-05-144-19/+270
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Pressing `T' in dired/dirvish on an audio file already transcribed it; on a video file it bounced with "Not an audio file". Real recordings ship as .mp4 / .mkv at least as often as raw .m4a, so the one-key flow ended at the wrong place. Pipeline now: - audio path -> direct into `cj/--start-transcription-process' (unchanged). - video path -> async ffmpeg extracts the audio track to a temp .mp3 under `temporary-file-directory' (libmp3lame, VBR q:a 4, ~165kbps -- right size for speech, accepted by every backend), then transcribes that file with the temp marked for cleanup after the transcription sentinel fires. Surface changes: - `cj/video-file-extensions' added to user-constants.el (mp4, mkv, mov, webm, avi, m4v, wmv, flv, mpg, mpeg, 3gp, ogv). - New predicates `cj/--video-file-p' / `cj/--media-file-p'. - New `cj/--extract-audio-from-video' (async ffmpeg with success callback; surfaces `cj/--notify' on failure; user-errors if ffmpeg isn't on PATH). - `cj/--start-transcription-process' gains optional `cleanup-file'. Sentinel deletes it after the existing logic runs. Backwards compatible -- the audio flow doesn't pass it. - `cj/transcribe-audio' renamed to `cj/transcribe-media' (dispatcher on audio vs video). `cj/transcribe-audio-at-point' renamed to `cj/transcribe-media-at-point'. Both old names kept as `defalias' so M-x history and any external references still work. - `T' in dired-mode-map + dirvish-mode-map points at `cj/transcribe-media-at-point'. - Module commentary USAGE block updated. 15 new ERT tests in `tests/test-transcription-video.el' cover the predicates (happy/boundary/error), ffmpeg invocation (correct args + missing-ffmpeg path), the dispatcher (audio direct, video via extraction, non-media rejected), the aliases, and the T binding. One existing test in `test-transcription-status-and-commands.el' updated to stub the new delegate name. Verified locally that ffmpeg is on PATH with libmp3lame, and that the exact arg list my code uses produces a valid MP3 from a synthetic test video.
* chore(todo): add task to extend dired T to transcribe videosCraig Jennings2026-05-141-0/+39
|
* refactor: clear transcription C-; T menu, move telega launcher to C-; TCraig Jennings2026-05-143-33/+20
| | | | | | | | | | | | | | | | The transcription menu wasn't earning its top-level keymap slot -- the commands (transcribe-audio, switch-backend, view-transcriptions, kill-transcription) are run rarely enough that `M-x' is fine. Drop the `cj/transcribe-map' keymap, its `(keymap-set cj/custom-keymap "T" ...)' binding, and the which-key labels. Commands stay callable by name. That frees `C-; T' for telega, where the mnemonic actually fits. Move the launcher from `C-; G' to `C-; T'. Update the which-key label, the module commentary, and the keymap-binding test assertion. The dashboard `g' single-letter binding stays put -- `t' there is vterm, so dashboard letters and the global `C-;' prefix don't share a key space anyway.
* refactor(org-config): flatten table ops directly under the org menuCraig Jennings2026-05-142-19/+34
| | | | | | | | | | | | | | Drop the `T' sub-prefix so table operations sit directly under `C-; O': `O r i' / `O r d' for rows, `O c i' / `O c d' for columns. Move `cj/org-clear-element-cache' from `c' (which now hosts the table-column sub-prefix) to capital `C'. Single-key org commands under this menu live on capitals from here on so the lowercase letters stay free for table sub-prefixes. Drop `cj/org-table-map' entirely -- its bindings now live directly on `cj/org-map'. Three tests in `test-org-config-keymap-ownership.el' updated/added: `C' for clear-cache, plus row and column binding assertions.
* refactor(org-config): move org-table-map under the org menuCraig Jennings2026-05-141-9/+11
| | | | | | | | | | | | | | | | `(keymap-set cj/custom-keymap "T" cj/org-table-map)' at top level silently collided with `cj/transcribe-map' bound to the same key in `modules/transcription-config.el'. Whichever module loaded last won, the other prefix became unreachable, and which-key still showed both labels in their respective sections -- so the visible documentation didn't match what actually fired. Move the table map under the existing `cj/org-map' (`C-; O') as the "T" sub-prefix, so `C-; T r i' becomes `C-; O T r i' and friends. The org menu only had one entry before (clear element cache); table operations are a natural neighbor. Frees `C-; T' at the top level for the transcription menu, which was the only other module fighting over it.
* feat(telega-config): guard launcher with a helpful message when telega is ↵Craig Jennings2026-05-143-5/+47
| | | | | | | | | | | | | | | | | | | | missing Without the guard, both `C-; G' and the dashboard Telegram icon trigger telega's autoload stub directly. When the package isn't installed yet the user sees `Cannot open load file: telega' in `*Messages*' with no hint about what to do. Wrap the launcher in `cj/telega' that checks `featurep' / `locate-library' first. If telega is present, delegate to it. Otherwise signal a `user-error' pointing at `scripts/setup-telega.sh' and the manual `M-x package-install RET telega' fallback. Rebind `C-; G' and the dashboard "g" key + Telegram icon callback to the wrapper. Two new tests in `test-telega-config.el' cover the wrapper paths (absent -> user-error with the recovery hint; present -> delegates to `telega') alongside the updated binding assertion.
* feat(setup-telega): install the telega Emacs package alongside docker setupCraig Jennings2026-05-142-2/+88
| | | | | | | | | | | | | | | | | | | | modules/telega-config.el uses `:ensure nil' on the use-package block (a stale MELPA archive index can 404 and take startup down if auto-install runs in init). The trade-off was that a fresh clone needed a one-time `M-x package-install RET telega' before the dashboard launcher or `C-; G' would work -- the autoload stub would fail with `Cannot open load file: telega' instead. Hit it on this machine just now: dashboard pressed, autoload tried to load telega.el, no telega.el on the load-path, cryptic error. Add `ensure_telega_package' to the setup script: probe with `(package-installed-p 'telega)' under `emacs --batch'; if absent, refresh MELPA and install via package.el; if that fails, surface the manual recovery path. Wire it into `main' after the docker checks. Four new bats tests cover the missing-emacs, already- installed, install-succeeds, and install-fails paths with `emacs' stubbed at the function level.
* chore(todo): close the coverage-below-70 parent + two child tasksCraig Jennings2026-05-141-28/+45
|
* refactor(system-commands): use string interactive spec so undercover instrumentsCraig Jennings2026-05-142-2/+32
| | | | | | | | | | | | | | | | `cj/system-cmd' had `(interactive (list (read-shell-command "System command: ")))' -- the destructured-list interactive spec. Undercover.el relies on edebug instrumentation, which doesn't see past that form, so the entire function body registered as 0 hits under coverage even though tests call the function directly. Switch to the equivalent string spec `(interactive "sSystem command: ")'. Same UX (prompt, history, single-string result), but the body now instruments correctly and coverage moves from 34/49 to 50/51. Add one more test that captures the `run-at-time' lambda in `cj/system-cmd-restart-emacs' and invokes it directly so the inner `call-process-shell-command' branch registers, taking coverage to 51/51.
* test(system-defaults): switch to single top-level require so undercover ↵Craig Jennings2026-05-141-90/+106
| | | | | | | | | | | | | | | | | | | | | | | | instruments The helper-functions test was per-test reloading system-defaults.el via `(load ...)' inside a `cl-letf' sandbox that stubs the side-effecting primitives (server-start, set-locale-environment, etc). Tests passed, but the coverage gauge stayed stuck at 1/12 because undercover.el only instruments the first load of a matching source; subsequent re-loads inside test bodies don't get tracked, so the function bodies showed as uncovered even though every test called them. Rewrite the test to call `(require 'system-defaults)' once at top level, wrapped in the same `cl-letf' stubs. The functions get instrumented exactly once. Drop the now-unused per-test sandbox macro. Add two more tests for the `(when (memq ...))' list-without- comp guard and the non-string-message format branch so coverage reaches 12/12. (`test-system-defaults-vc-follow-symlinks.el' still uses the per-test `(load ...)' pattern because that test *is* the load-side-effect verification, not a function-body test.)
* chore(todo): close Python tree-sitter predicate bug as upstream-resolvedCraig Jennings2026-05-142-7/+32
| | | | | | | | | | | | | | | | | | | | The treesit-query-error redisplay flood diagnosed 2026-04-26 no longer reproduces. Versions: emacs 30.2-3 (was 30.2-2 at the time of the investigation, upgraded 2026-05-03), tree-sitter 0.26.8 (unchanged). The upstream Emacs version string is unchanged, but the Arch package revision bump most likely carries a downstream patch to treesit.c's predicate translation. Verified by re-running the documented repro: the exact failing query from python.el captures cleanly via `treesit-query-capture', and `font-lock-ensure' on a real .py file under `python-ts-mode' returns with no `treesit-query-error'. No local override needed. Mark the todo.org entry DONE, fix the stale `inbox/' path on the investigation-doc link (file now lives under `docs/'), update the cross-reference from the grammar-bootstrap task to note this no longer blocks it, and append a RESOLVED 2026-05-14 footer to the investigation doc so future-me can see why it got closed.
* chore(todo): reconcile test-coverage tracking with current stateCraig Jennings2026-05-141-35/+75
| | | | | | | | | | | After this session's coverage push (68.8% -> 86.5%), 28 of the 30 child modules listed in the coverage-below-70% task have crossed the threshold. Mark them DONE with their new percentages, leave the two genuinely-blocked modules (system-defaults.el at 8.3% and system-commands.el at 69.4%) as TODO with notes explaining the instrumentation-gap reason each is stuck. Also: drop the stray =p= from the parent heading.
* chore(todo): mark journal-save fix DONECraig Jennings2026-05-141-0/+32
|
* fix(org-roam-config): save journal buffer after copying DONE taskCraig Jennings2026-05-142-2/+33
| | | | | | | | | | | | | | `cj/org-roam-copy-todo-to-today' tried to save the target journal buffer via `org-after-refile-insert-hook' bound to `#'save-buffer', but that value is the wrong shape (single function instead of a hook list), and the only other save mechanism -- the `:after' advice on `org-refile' that calls `org-save-all-org-buffers' -- doesn't attach until `:defer .5' elapses, so the very first DONE transition after startup leaves the journal unsaved. Drop the broken hook binding and save the target buffer explicitly after the refile call. New ERT test asserts `buffer-modified-p' on the journal buffer is nil after the function returns.
* test(music-config): cover playlist load/save/edit/toggle/show + ↵Craig Jennings2026-05-141-0/+173
| | | | create-radio-station
* test(music-config): cover add-directory, fuzzy-select, playlist-clear, ↵Craig Jennings2026-05-141-0/+191
| | | | next/previous, consume-toggle
* test(ai-config): cover available-backends, change-model, add-file, toggle, ↵Craig Jennings2026-05-141-0/+160
| | | | context-clear
* test(transcription-config): cover notify, start-process, sentinel bodiesCraig Jennings2026-05-141-0/+165
|
* test(dirvish-config): cover ediff-files, create-playlist, set-wallpaper wrappersCraig Jennings2026-05-141-0/+144
|
* test(org-agenda-config): cover scan-files, todo-list wrappers, main-display, ↵Craig Jennings2026-05-141-0/+162
| | | | add-timestamp
* test(org-roam-config): cover copy-todo-to-today and move-org-branch-to-roam ↵Craig Jennings2026-05-141-0/+129
| | | | bodies
* test(custom-ordering): cover the interactive arrayify/listify/sort wrappersCraig Jennings2026-05-141-0/+145
|
* test(org-refile-config): cover cj/--org-refile-scan-targets disk walkerCraig Jennings2026-05-141-0/+142
|
* test(mail-config): cover toggle-smtpmail-debug, disable-auto-composition, ↵Craig Jennings2026-05-141-0/+70
| | | | mark-all-headers
* test(ui-theme): cover switch-themes, save-to-file, get-active-nameCraig Jennings2026-05-141-0/+110
|
* test(org-drill-config): cover drill-edit, drill-capture, drill-refileCraig Jennings2026-05-141-0/+91
|
* test(host-environment): cover cj/match-localtime-to-zoneinfoCraig Jennings2026-05-141-0/+58
|
* test(ui-navigation): cover split-and-follow + undo-kill-bufferCraig Jennings2026-05-141-0/+108
| | | | | | | | | | Sibling tests covered `toggle-window-split` and the window-resize sticky map. This batch covers: - `cj/split-and-follow-right`: split-window-right + other-window + consult-buffer in order. - `cj/split-and-follow-below`: split-window-below + other-window + consult-buffer in order. - `cj/undo-kill-buffer`: with no arg, opens the head of `recentf-list` that isn't currently visited; with N=1, opens the second entry; empty list -> no-op. Top-level defvars for `recentf-mode` and `recentf-list` so let-bindings reach the dynamic vars under lexical scope.
* test(coverage-elisp): cover project-root resolution, report-path, runCraig Jennings2026-05-141-0/+113
| | | | | | | | | | Sibling `test-coverage-elisp--detect.el` covered the detect heuristic. This batch fills in the rest: - `cj/--coverage-elisp-project-root`: explicit arg wins, falls back to projectile, falls back to `default-directory`. - `cj/--coverage-elisp-report-path`: appends `.coverage/simplecov.json` to the resolved root. - `cj/--coverage-elisp-run`: launches `make coverage` via `compilation-start`, fires the callback with the report path on `finished` status, skips the callback on failure. projectile and compilation-start are stubbed; the compilation buffer is a real buffer the test creates and tears down.
* test(system-utils): cover open-file-with-command, server-shutdownCraig Jennings2026-05-141-0/+94
| | | | | | | | | Sibling `test-system-utils-eval-buffer.el` covered the eval-buffer wrapper. This batch covers: - `cj/open-file-with-command`: a launcher routes through `call-process`; a non-launcher routes through `start-process-shell-command` into a dedicated `*Open with <cmd>: <file>*` buffer; a missing file signals an error. - `cj/server-shutdown`: saves buffers and calls `kill-emacs`. Process and prompt primitives are stubbed.
* test(system-commands): cover resolve, run wrapper, exit/restart, menuCraig Jennings2026-05-141-0/+142
| | | | | | | | | | | | Sibling `test-system-commands-keymap.el` locked the keymap shape. This batch covers the runtime helpers and commands: - `cj/system-cmd--resolve`: trims strings, errors on empty/non-string-non-symbol, round-trips a symbol whose value is a non-empty string, errors on a symbol with empty value. - `cj/system-cmd`: wraps a plain string in `nohup ... &` and hands it to `start-process-shell-command`; a confirm-tagged var with an N response signals user-error. - `cj/system-cmd-exit-emacs`: declining the prompt aborts; accepting calls `kill-emacs`. - `cj/system-cmd-restart-emacs`: declining aborts before scheduling; accepting schedules two timers. - `cj/system-command-menu`: the completing-read pick routes through `call-interactively` to the right command symbol. Top-level defvars for `test-sc-my-cmd` and `test-sc-empty-cmd` make the let-bindings dynamic so `symbol-value` reaches them under lexical scope.
* test(external-open): cover xdg-open, open-this-file-with, find-file-autoCraig Jennings2026-05-141-0/+120
| | | | | | | | | | Sibling tests in `test-external-open-lib-*.el` covered the pure helpers (`cj/external-open-command`, `cj/external-open-launcher-p`). This batch covers the user-facing wrappers: - `cj/xdg-open`: posix path triggers `call-process` with the open program; errors when no file is associated; errors when no command resolves on the host. - `cj/open-this-file-with`: errors outside a file-visiting buffer; posix path spawns a detached process via `call-process-shell-command` with `nohup ... >/dev/null 2>&1 &`. - `cj/find-file-auto`: routes a `.mp4` (in `default-open-extensions`) to `cj/xdg-open`, passes `.txt` through to the original `find-file`, and falls through cleanly for a nil filename argument. Host predicates, call-process, and the underlying `cj/xdg-open` are stubbed throughout.
* test(prog-go): cover go-setup, staticcheck, debug, keybindingsCraig Jennings2026-05-141-0/+144
| | | | | | | | | | | Same shape as the prog-python and prog-webdev setup tests: company-mode + electric-pair-mode + LSP gating + buffer-local preferences. New tests cover: - `cj/go-setup`: tab-width 4, standard-indent 4, indent-tabs-mode t (Go convention); company-mode + electric-pair-mode both fire; LSP starts when gopls is on PATH, skips otherwise. - `cj/go-staticcheck`: runs `compile` with `./...` when staticcheck is on disk; messages and skips compile otherwise. - `cj/go-debug`: starts `gud-gdb` with `dlv debug` when delve is on PATH; messages otherwise. - `cj/go-mode-keybindings`: wires `C-; f` -> gofmt, `S-<f5>` -> staticcheck, `S-<f6>` -> debug. External modes and process primitives are stubbed.
* test(org-webclipper): cover lazy init, protocol handler, EWW captureCraig Jennings2026-05-141-0/+167
| | | | | | | | | | | Sibling `test-org-webclipper-process.el` covers the content-processing helper. This batch fills in the rest: - `cj/webclipper-ensure-initialized`: registers the webclip protocol entry + the W and w capture templates on first call, is idempotent on subsequent calls. - `cj/org-protocol-webclip`: stashes the url+title, triggers capture; missing title falls back to "Untitled". - `cj/org-protocol-webclip-handler`: errors when no url stashed, returns processed org content on success (with the first heading stripped + subs demoted), wraps fetch failures in a "Failed to clip" error. - `cj/org-webclipper-EWW`: routes through `org-eww-copy-for-org-mode` for eww-mode and `org-w3m-copy-for-org-mode` for w3m-mode; errors on any other source mode. Top-level defvars for `org-protocol-protocol-alist`, `org-capture-templates`, and `webclipped-file` make let-bindings dynamic under lexical scope. org-web-tools and the eww/w3m copy commands are stubbed.
* test(org-refile-config): cover refresh-targets, org-refile, refile-in-fileCraig Jennings2026-05-141-0/+82
| | | | | | | | | | Sibling tests covered the ensure-org-mode helper and the build-targets pipeline. The three wrapper commands were uncovered: - `cj/org-refile-refresh-targets`: passes the `force-rebuild` flag to `cj/build-org-refile-targets`. - `cj/org-refile`: builds the cache, then calls `org-refile` with the four positional args. - `cj/org-refile-in-file`: scopes `org-refile-targets` to the current file at maxlevel 6, then saves after the refile completes. Top-level `defvar` for `org-refile-targets` so the let-binding inside the function is dynamic under lexical scope.
* test(org-contacts-config): cover template helpers, props-matching, email ↵Craig Jennings2026-05-141-0/+129
| | | | | | | | | | | | | | aggregator Sibling tests covered the capture-finalize hook and the email-string parser. This batch fills in the rest: - `cj/org-contacts-template-name` / `-email`: fall back to `read-string` outside mu4e; pull from `mu4e-message-field` when inside. - `cj/org-contacts-new`: delegates to `org-capture` with key "C". - `cj/org-contacts--props-matching`: filters an entry's props by regexp. - `cj/get-all-contact-emails`: formats each entry as "Name <email>", expands multi-email strings. - `cj/insert-contact-email`: inserts the completing-read selection at point. mu4e and org-contacts primitives are stubbed.
* test(org-reveal-config): cover command wrappers + preview helpersCraig Jennings2026-05-141-0/+197
| | | | | | | | | | | | | | | Sibling tests covered the header template, title-to-filename slug, and the headers-remove pass. This file fills in the rest: - `cj/--reveal-preview-export-on-save`: exports in org-mode, skips otherwise. - `cj/--reveal-ensure-header`: inserts when absent, no-op (no prompt) when already present. - `cj/reveal-export`: errors outside org-mode, opens HTML in browser otherwise. - `cj/reveal-preview-start`: installs the buffer-local after-save-hook + exports once; errors outside org-mode. - `cj/reveal-preview-stop`: removes the hook + messages. - `cj/reveal-insert-header`: errors outside org-mode, errors when headers already present, inserts and reports otherwise. - `cj/reveal-remove-headers`: errors outside org-mode, messages the removed line count. - `cj/reveal-new`: errors when target file already exists. ox-reveal's `org-reveal-export-to-html` and `browse-url-of-file` are stubbed.
* test(org-noter-config): cover document path, find/create, session, start, insertCraig Jennings2026-05-141-0/+243
| | | | | | | | | | | | | | | Sibling tests covered the preferred-split, title-to-slug, notes-template, and in-document / in-notes-file predicates. This batch fills in the rest: - `cj/org-noter--get-document-path`: pdf-view-mode uses buffer-file-name, nov-mode uses `nov-file-name`, unrelated mode returns nil. - `cj/org-noter--extract-document-title`: strips the extension. - `cj/org-noter--find-notes-file`: returns the file containing the doc-path, nil when no doc or no match. - `cj/org-noter--create-notes-file`: writes the template when absent. - `cj/org-noter--session-active-p`: nil when unbound, non-nil when set. - `cj/org-noter--toggle-notes-window`: deletes when visible, requests start when hidden. - `cj/org-noter-start`: routes through the cond -- toggle in doc+session, switch-window in notes+session, message elsewhere. - `cj/org-noter-insert-note-dwim`: with active session inserts directly; without one, starts then inserts. org-noter / pdf-view / nov / org-id primitives are stubbed.
* test(slack-config): cover credentials, start/stop, reactions, notify, kill-allCraig Jennings2026-05-141-0/+251
| | | | | | | | | | | | | | | | Sibling `test-slack-config-reactions.el` covered the post-command-hook safety advice and the empty-buffer guard. This batch covers the rest: - `cj/slack--get-credential`: string secret, function secret, missing entry. - `cj/slack-start`: errors when token / cookie missing, registers + starts when both present. - `cj/slack-stop`: calls `slack-ws-close` + messages. - `cj/slack--reaction-candidates`: includes the (Other...) escape hatch. - `cj/slack-select-reaction`: emoji-name return for a curated pick, delegation to `slack-message-reaction-input` for Other. - `cj/slack-notify`: fires for IMs (not self), skips self-messages and non-IM non-mentions. - `cj/slack-test-notify`: fires the notify pipeline directly. - `cj/slack-mark-read-and-bury`: marks via the latest-ts + buries; outside slack, just buries. - `cj/slack-close-all-buffers`: closes buffers with `slack-current-buffer` local, leaves non-slack buffers alone. The close-all assertions check identity (the 2 slack buffers killed, the non-slack one preserved) instead of an exact total -- ERT-internal buffers leaking into `(buffer-list)` from earlier tests would otherwise inflate the count, and `cl-letf` over the `buffer-list` subr is unreliable under native-comp.