<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/prog-general.el, branch main</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-06-01T13:44:03+00:00</updated>
<entry>
<title>fix(prog-general): repoint daily-prep opener to root symlink</title>
<updated>2026-06-01T13:44:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-01T13:44:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=4772d49efd4b0b6031496caac1777915da6204a0'/>
<id>urn:sha1:4772d49efd4b0b6031496caac1777915da6204a0</id>
<content type='text'>
The daily-prep workflow now keeps its stable symlink at the project root as daily-prep.org instead of inbox/today-prep.org. I repointed cj/open-project-daily-prep (C-c p d) to match, updating its docstring, not-found message, and test for the new path.
</content>
</entry>
<entry>
<title>refactor(prog): open daily-prep respecting the window split</title>
<updated>2026-05-27T20:08:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-27T20:08:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=9b04860a22b30db746bbe4cd3376383cc19432ea'/>
<id>urn:sha1:9b04860a22b30db746bbe4cd3376383cc19432ea</id>
<content type='text'>
C-c p d (cj/open-project-daily-prep) always forced the prep doc into another window. I switched it to cj/--find-file-respecting-split, the same helper the sibling C-c p t (project todo) uses: it opens the other window when the frame is split and reuses the current window when it isn't. The two project-open commands now behave the same way.
</content>
</entry>
<entry>
<title>fix(prog-general): require user-constants for its config constants</title>
<updated>2026-05-26T22:41:32+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-26T22:41:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=1d0b78e2ab7d226976c5e9b97ef120b6f6e897d7'/>
<id>urn:sha1:1d0b78e2ab7d226976c5e9b97ef120b6f6e897d7</id>
<content type='text'>
prog-general uses code-dir, projects-dir, and snippets-dir (all from user-constants) in its projectile and yasnippet configs, but it only declared them as compile-time defvars and leaned on init.el loading user-constants first. That load-order assumption broke when the test suite ran combined: if another test file loaded prog-general before user-constants, yasnippet's :config hit a void snippets-dir and yas-global-mode never enabled, so eight yas-activation tests failed.

I replaced the three compile-time defvars with a runtime (require 'user-constants) so the module declares its real dependency and is self-contained. The combined prog-general suite is now 15/15, and the module no longer depends on init.el's load order for constants it reads at load time.
</content>
</entry>
<entry>
<title>feat(projectile): open the project daily prep on C-c p d</title>
<updated>2026-05-26T22:01:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-26T22:01:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=8e5efcab4043ef9824456e96f056bb99440b3ec4'/>
<id>urn:sha1:8e5efcab4043ef9824456e96f056bb99440b3ec4</id>
<content type='text'>
I added cj/open-project-daily-prep on C-c p d. It opens inbox/today-prep.org under the Projectile project root in another window, project-scoped, so a project without a prep file just reports it rather than erroring. The binding had only ever been eval'd live into the daemon in a past session and vanished on the next restart, so this persists it to the module.

Freeing d meant reworking the deadgrep bindings. deadgrep-in-dir moves to C-c p G (replacing plain deadgrep, which stays M-x-callable), and deadgrep-here keeps C-c p g. Plain project-wide deadgrep dropped off the projectile prefix because it overlapped the context-aware and arbitrary-directory variants. Tests cover the open, missing-file, and not-in-a-project paths.
</content>
</entry>
<entry>
<title>fix(prog-general): open the project todo in the other window when split</title>
<updated>2026-05-25T13:00:20+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-25T13:00:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=92eaba30ae35727509f1d9d6dcc467c248f627dc'/>
<id>urn:sha1:92eaba30ae35727509f1d9d6dcc467c248f627dc</id>
<content type='text'>
C-c p t (cj/open-project-root-todo) called find-file, which always opened todo.org in the selected window, replacing whatever I was looking at. Now it opens in the other window when the frame is split and in the current window when it isn't, through a small cj/--find-file-respecting-split helper. The helper is a top-level defun rather than buried in the projectile :config block so it can be unit-tested without loading projectile.

I left cj/project-switch-actions alone. Opening the todo on a project switch is a different trigger and not what this fixes.
</content>
</entry>
<entry>
<title>docs(load-graph): classify programming modules</title>
<updated>2026-05-24T21:32:07+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T21:32:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=219018602f817bffedbb3d157fd9267d21f97098'/>
<id>urn:sha1:219018602f817bffedbb3d157fd9267d21f97098</id>
<content type='text'>
Sixth classification batch: prog-general plus the language modules — prog-c, prog-go, prog-lisp, prog-python, prog-webdev, prog-json, prog-yaml, prog-shell, prog-training. I annotated each header, added a Batch 6 table to the inventory, and extended the validation allowlist. 52 of 102 modules are now classified.

prog-general owns the shared defaults and tree-sitter/LSP policy and stays eager. The language modules are eager only by init order and should load by major mode, so they're tagged Phase 6 deferral candidates. prog-shell's after-save executable hook is the one side effect worth scoping. No new hidden dependencies.
</content>
</entry>
<entry>
<title>feat(yas): activate yasnippet globally with fundamental-mode extras</title>
<updated>2026-05-15T20:10:19+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-15T20:10:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=74cffcac0c9bb8e4a7ee33d51ff1f2cd9a2cd7f0'/>
<id>urn:sha1:74cffcac0c9bb8e4a7ee33d51ff1f2cd9a2cd7f0</id>
<content type='text'>
The yasnippet use-package block switches from `:hook (prog-mode . yas-minor-mode)` to `:demand t` + `(yas-global-mode 1)`. That makes yas-minor-mode active in every buffer, not just prog-mode-derived ones.

I added a small helper, `cj/--yas-activate-fundamental-extras`, attached as `:hook (yas-minor-mode . ...)`. It calls `(yas-activate-extra-mode 'fundamental-mode)` so the snippet table at `snippets/fundamental-mode/` is consulted in every buffer regardless of the buffer's own major mode. That's what makes universal triggers like `&lt;cj` work everywhere.

The new `tests/test-prog-general-yas-activation.el` covers both wiring (yas-global-mode on, fundamental-mode in yas-extra-modes, yas-minor-mode active in org/text buffers) and end-to-end expansion (the marker snippet expands correctly in fundamental, text, org, emacs-lisp, and python-ts modes). 9 tests, all green; full unit suite green with no regressions.
</content>
</entry>
<entry>
<title>chore(prog-general): disable auto-close of *compilation* window</title>
<updated>2026-05-03T22:39:10+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-03T22:39:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=2a60405ac28c12ec63fac2032b8f87599ebfc6b6'/>
<id>urn:sha1:2a60405ac28c12ec63fac2032b8f87599ebfc6b6</id>
<content type='text'>
I commented out the global `compilation-finish-functions' hook that closed the *compilation* window 1.5 seconds after a successful compile. With the F6 test runner now landing test output in *compilation*, I want the buffer to stay open afterward so I can read the results, not have it slide out from under me.

The block stays in the file as a commented-out reference so I can flip it back on later if I want. A prog-mode-only variant is noted in the comment for the day I want the auto-close back for non-prog compiles (org-export, etc.) — that needs advice on `compile' to capture the originating buffer's `major-mode' at compile-start, since the hook fires after `compilation-mode' has already taken over the current buffer. Skipped for now per the simpler path.
</content>
</entry>
<entry>
<title>feat(dev-fkeys): add project-aware F4 compile/run dispatcher</title>
<updated>2026-05-03T21:13:21+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-03T21:13:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=2c94acd52cc92dc4ebefd999dbca771367cc3090'/>
<id>urn:sha1:2c94acd52cc92dc4ebefd999dbca771367cc3090</id>
<content type='text'>
I added a new module `modules/dev-fkeys.el` that owns the dev F-key block. F4 prompts via `completing-read` with a candidate set filtered by project type (compiled / interpreted / unknown). C-F4 is the compile-only fast path. M-F4 is clean + rebuild. It runs a heuristic clean command derived from the project markers (go.mod, Cargo.toml, Eask, Makefile, CMakeLists.txt) and chains `projectile-compile-project` on success. S-F4 stays on `recompile` and now lives globally instead of duplicated across prog-general.el and prog-c.el. F6 is bound globally to `projectile-test-project` as a Phase 1 stopgap. Phase 2 replaces it with the polyglot test runner spec'd in todo.org.

Project-type detection runs against the projectile root and falls back to `unknown` when no marker matches. Interpreted markers are checked first so a Python or Node project with a Makefile for tasks classifies as interpreted instead of compiled. Compile + Run sequencing uses a one-shot `compilation-finish-functions` hook that self-removes on first invocation and only fires the follow-up when the status string starts with `finished`.

Cleanup in the same commit:
- Dropped F4/F5/F6 from `prog-general.el`'s prog-mode-hook. They are now global.
- Dropped F6→format bindings from prog-c.el / prog-python.el / prog-shell.el. C-; f was already bound in each, so this is pure removal.
- Dropped the duplicate S-F4 from prog-c.el. The global binding covers it.
- Updated the keybinding header in prog-general.el and the workflow comments in prog-c.el / prog-shell.el.
- Wired `(require 'dev-fkeys)` in init.el alongside coverage-core.

TDD: 73 tests across 11 files, one per helper. Production code is split into small testable internals (`cj/--detect-project-type`, `cj/--f4-candidates`, `cj/--f4-derive-clean-cmd`, `cj/--f4-make-once-hook`, `cj/--f4-dispatch`, `cj/--f4-compile-and-run-impl`, `cj/--f4-clean-rebuild-impl`, `cj/--f4-project-root`) plus three thin interactive wrappers. Smoke tests confirm bindings register on load.

Known limitation: if another `compilation-finish-functions` hook fires between my add-hook and the compile finishing, the chain can fire on the wrong compile. The hook self-removes on first invocation regardless of which compile it sees. Documented in the impl docstring. Acceptable for v1.

Phase 2 will replace F6 with the polyglot test runner (tree-sitter queries for Python/Go/TS, sexp scan for Elisp, buffer-local last-test memory).
</content>
</entry>
<entry>
<title>refactor: Replace doom-modeline with mood-line and remove deprecated tree-sitter</title>
<updated>2025-11-03T21:43:36+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2025-11-03T21:43:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=05c8126602905d805ddc2a4448436c9c4adb12fc'/>
<id>urn:sha1:05c8126602905d805ddc2a4448436c9c4adb12fc</id>
<content type='text'>
Method 2 improvements for cleaner, faster configuration:

1. **Replaced doom-modeline with mood-line** (modules/modeline-config.el)
   - Simplified from 70+ lines to ~10 lines (-40 lines net)
   - mood-line is lightweight, minimal, inspired by doom-modeline
   - Better performance with no dependencies
   - Keeps all essential features: buffer status, major mode, VCS,
     flycheck, cursor position, multiple-cursors counters

2. **Removed deprecated tree-sitter package** (modules/prog-general.el)
   - Deleted `(use-package tree-sitter)`
   - Now relies solely on Emacs 29+ built-in treesit with treesit-auto
   - treesit-auto continues to manage grammars automatically
   - No functionality lost, cleaner dependency tree

Both changes serve Method 2: "Stop Problems Before They Appear"
- Simpler code = fewer bugs
- Fewer dependencies = less maintenance
- Native features = better integration

Updated todo.org to mark both tasks complete [2/5 in Method 2].
</content>
</entry>
</feed>
