<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/music-config.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-05-27T19:36:57+00:00</updated>
<entry>
<title>feat(window): remember a side window's size across toggles</title>
<updated>2026-05-27T19:36:57+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-27T19:36:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=84d8ab6a3ad97697a717a770c42010e9ec9076e5'/>
<id>urn:sha1:84d8ab6a3ad97697a717a770c42010e9ec9076e5</id>
<content type='text'>
The F10 music playlist opened at a fixed fraction every time, so any manual resize was lost the moment it was toggled closed. Now the toggle captures the window's size on close and reopens at that height, for the rest of the session.

The mechanism is generic, not music-specific. cj/window-size-fraction (geometry-lib) is the pure kernel: a clamped window/frame ratio. cj/side-window-capture-size and cj/side-window-display (toggle-lib) wrap it for any display-buffer-in-side-window consumer — height for top/bottom, width for left/right — storing the remembered fraction in a caller-supplied state var. It mirrors the direction-split toggle pattern the vterm dispatchers already use, but for atomic side windows that can't be split.

music-config wires F10 to it: cj/music-playlist-window-height is the default, cj/--music-playlist-height holds the remembered value (in-memory, resets each session).

12 new tests across the two libs, Normal/Boundary/Error each covered.
</content>
</entry>
<entry>
<title>refactor(load-graph): route C-; registration through the keymap API</title>
<updated>2026-05-25T00:59:28+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-25T00:59:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=08014b2f15e099a1c5e662a17a41290f37aeebf4'/>
<id>urn:sha1:08014b2f15e099a1c5e662a17a41290f37aeebf4</id>
<content type='text'>
Migrated all 31 cj/custom-keymap registration sites across 24 modules from direct (keymap-set cj/custom-keymap ...) calls to cj/register-prefix-map and cj/register-command. Consumers no longer reference cj/custom-keymap directly, so keybindings.el is the sole owner of the C-; prefix and modules reach it only through the API (each already requires keybindings from Phase 2).

Behavior-preserving: I dumped every C-; binding before and after the migration and they're identical: 279 bindings, each resolving to the same command. The which-key label blocks are untouched, since they use string key descriptions and never assumed the keymap existed. I byte-compiled all 24 files (no new free-variable warnings, because the cj/custom-keymap references are gone), and make test, validate-modules, and an init load all pass.
</content>
</entry>
<entry>
<title>docs(load-graph): classify remaining domain and optional modules</title>
<updated>2026-05-24T22:01:40+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T22:01:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=f84bba186dca1543f9c5f02c03af355188b6e87c'/>
<id>urn:sha1:f84bba186dca1543f9c5f02c03af355188b6e87c</id>
<content type='text'>
Final classification batch: the last 19 modules — linear-config, local-repository, lorem-optimum, mail-config, markdown-config, music-config, pdf-config, quick-video-capture, reconcile-open-repos, restclient-config, slack-config, system-commands, telega-config, tramp-config, transcription-config, video-audio-recording, vterm-config, weather-config, wrap-up. I annotated each header, added a Batch 9 table to the inventory, and extended the validation allowlist. 101 of 102 modules are now classified; only elfeed-config remains, deferred on its test fix.

Two more hidden dependencies turned up. video-audio-recording uses the boundp shim for its C-; r binding, and mail-config registers C-; e directly without requiring keybindings, so it errors standalone rather than degrading. Both recorded for Phase 2.
</content>
</entry>
<entry>
<title>chore(modules): pass validate-modules in batch by adding requires</title>
<updated>2026-05-08T00:25:29+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-08T00:25:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a41ef9774f6550da446a3ae8fbbcbcd5bf6c23c4'/>
<id>urn:sha1:a41ef9774f6550da446a3ae8fbbcbcd5bf6c23c4</id>
<content type='text'>
`make validate-modules` had 19 module-load failures, all the same shape: a module references a symbol or feature owned by another module without saying so. Production was fine because init.el orders requires correctly. The batch target loads each module in isolation, though, and surfaces the gap.

I added explicit `(require 'keybindings)` or `(require 'user-constants)` to each affected module. The requires are idempotent at runtime, so production load order is unchanged. For three optional packages (elpa-mirror, mu4e, org-contacts), I switched to `(require 'X nil t)` so the modules load cleanly when those packages aren't installed. The activation calls become no-ops in that case.

`make validate-modules` now reports 0 failures.
</content>
</entry>
<entry>
<title>feat(music): add random-aware next/previous; refactor music + calendar-sync</title>
<updated>2026-04-03T13:33:33+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-03T13:33:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=6cb923b4fb9ae66258a9eeef0d67d7e950daa737'/>
<id>urn:sha1:6cb923b4fb9ae66258a9eeef0d67d7e950daa737</id>
<content type='text'>
Music: random mode now respected by next/previous keys. Previous navigates
a 50-track play history ring buffer. Fixed playlist replacement bug.
24 new tests.

Calendar-sync: consolidated duplicate parse functions, extracted timezone
localization helper, unified expand-daily/monthly/yearly into parameterized
function, removed dead code. 33 new characterization tests. -90 lines.
</content>
</entry>
<entry>
<title>feat(music): add test coverage for 7 functions, refactor with extracted helpers</title>
<updated>2026-04-01T13:13:33+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-04-01T13:13:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=94a8221668c3ce96daf7c3b062c5071c03bb20b4'/>
<id>urn:sha1:94a8221668c3ce96daf7c3b062c5071c03bb20b4</id>
<content type='text'>
Add 47 new unit tests across 7 test files covering playlist-modified-p,
assert-valid-playlist-file, playlist-tracks, create-radio-station,
ensure-playlist-buffer, after-playlist-clear, and header-text.

Extract three helpers to reduce duplication: assert-m3u-files-exist (dedupes
2 identical guards), sync-playlist-file (dedupes 3 state-sync patterns),
and select-m3u-file (reusable M3U selection with cancel). Simplify
append-track-to-playlist nesting from 6 to 4 levels. Delete unused
cj/music-keymap-prefix variable.
</content>
</entry>
<entry>
<title>fix(music): place point on first track after playlist load/reload</title>
<updated>2026-03-10T12:24:25+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-03-10T12:24:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=699f5ba8e51a90272bf80191eae72d84d7dbb71a'/>
<id>urn:sha1:699f5ba8e51a90272bf80191eae72d84d7dbb71a</id>
<content type='text'>
</content>
</entry>
<entry>
<title>fix(music): force case-insensitive search when adding songs</title>
<updated>2026-02-21T13:01:38+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-02-21T13:01:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=17050d2ebbe926894d10b540e346ae85dae4e464'/>
<id>urn:sha1:17050d2ebbe926894d10b540e346ae85dae4e464</id>
<content type='text'>
Bind orderless-smart-case to nil in cj/music-fuzzy-select-and-add
so typing uppercase characters doesn't switch to case-sensitive matching.
</content>
</entry>
<entry>
<title>feat(music): add playlist UI with header overlay, track styling, and tests</title>
<updated>2026-02-15T20:31:36+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-02-15T20:31:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=1242a731cbe9ffc8f223ce82795b3cd8f79d1216'/>
<id>urn:sha1:1242a731cbe9ffc8f223ce82795b3cd8f79d1216</id>
<content type='text'>
Replace raw file paths with clean track descriptions (Artist - Title [M:SS]),
add multi-line header overlay showing playlist info, now-playing, mode
indicators with gold/muted toggle states, and keybinding hints. Style
non-playing tracks in Dupre steel, playing track in Dupre gold. Playlist
window now opens from the bottom at 50% height with subtle background
highlight on focus.

Unit tests for format-duration (13 tests) and track-description (16 tests).
</content>
</entry>
<entry>
<title>docs(music): add ncmpcpp keybinding comparison table to commentary</title>
<updated>2026-02-15T07:07:53+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-02-15T07:07:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=f5955467babd5995b394d57e1f102ff221b6cf85'/>
<id>urn:sha1:f5955467babd5995b394d57e1f102ff221b6cf85</id>
<content type='text'>
Document playlist-mode keybindings with ncmpcpp default alignment
status (83% match). Note intentional divergences (SPC/p swap,
x=consume vs crossfade) and EMMS-only features.
</content>
</entry>
</feed>
