aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* docs(specs): retire the gloss spec, close signal-client as implementedCraig Jennings26 hours2-324/+2
| | | | The gloss spec described a repo scaffold and implementation that shipped months ago (the package lives at its own repo and gloss-config.el already wires it in) — the file was a stale artifact, deleted on Craig's call. signal-client flips to IMPLEMENTED: v1 is in daily use, and the messenger-unification spec designates the smoke project as the ground-up successor, so further client work happens there.
* fix(prog-python): keep the pyright guard authoritative for LSP attachCraig Jennings26 hours2-5/+78
| | | | | | lsp-pyright's :hook lambda called require and lsp-deferred unguarded on every python-ts buffer, so a machine without pyright still got the LSP attach prompt that cj/python-setup's guard exists to prevent. The guarded branch now owns the require and the attach, and the hook is gone. Classic python-mode now runs the same setup hooks as python-ts-mode, so treesit-auto's grammar-unavailable fallback keeps indentation, keys, and LSP. Four tests cover the guard branches and pin that every python hook entry stays a named function.
* fix(flycheck): drop the checkdoc suppression that never workedCraig Jennings26 hours1-4/+6
| | | | The :custom block set checkdoc-arguments, a variable that doesn't exist. Checkdoc has no such option and this flycheck runs checkdoc through a fixed subprocess form, so the intended suppression of two warning types never happened. Removing it changes no behavior. If those checkdoc warnings need silencing, that's a feature against flycheck-emacs-lisp-checkdoc-form.
* fix(prog-lisp): let flycheck-package setup actually runCraig Jennings26 hours1-1/+5
| | | | :after (flycheck package-lint) waits for both features, but nothing loads package-lint on its own (it's flycheck-package's dependency, pulled in by the require), so the setup never ran and elisp buffers never got the package-lint checker. Keying on flycheck alone loads the chain.
* fix(prog-json): make the jq query key actually reachableCraig Jennings26 hours1-3/+8
| | | | C-c C-q was bound via :bind (:map json-ts-mode-map) inside the jq-mode use-package, which defers the binding to jq-mode's load. Nothing ever loaded jq-mode, so the key was dead. The binding now keys on json-ts-mode's load, and jq-interactively's autoload pulls jq-mode in on first press.
* fix(prog-training): stop enabling global url.el debug loggingCraig Jennings26 hours1-2/+3
| | | | leetcode's :custom set url-debug t, a debugging leftover that turned on url.el request logging for the entire session the moment leetcode loaded. I also declared code-dir for the compiler.
* feat(telega): enable desktop notificationsCraig Jennings27 hours1-1/+8
| | | | Incoming Telegram messages were invisible unless their buffer was on screen; telega ships notifications but leaves the mode off. telega-notifications-mode now turns on in the package's :config, so it activates when telega loads and respects telega's own per-chat mutes. Routing through a shared messenger notifier stays with the unification task.
* fix(signal): load notifications.el before the fallback notifierCraig Jennings27 hours1-0/+3
| | | | The script-absent fallback called notifications-notify, which isn't autoloaded, so a fresh session without the notify script would die on void-function instead of showing the toast. The fallback now requires notifications.el when the function is unbound. Found while giving slack-config the same fallback.
* fix(slack): harden notifications like signel'sCraig Jennings27 hours2-6/+159
| | | | | | cj/slack-notify passed raw message bodies to a bare start-process. A multiline message made a giant toast, and a machine without the notify script errored inside the condition-case, so the notification silently vanished. It now routes through the same shape signel uses: whitespace collapsed and the body truncated at 120 chars, sound gated by a new cj/slack-notify-sound defcustom (silent by default), and a notifications-notify fallback when the script is absent. The fallback requires notifications.el first, which isn't autoloaded. cj/slack-test-notify exercises the same delivery path. The shared cj/messenger-notify extraction that collapses the signel and slack copies stays with the messenger-unification task. Ten tests cover the formatter, the delivery routing, and the DM/mention predicate wiring the audit called untested.
* fix(signal): honor the cache-clear promise and mark empty fetches warmCraig Jennings27 hours3-11/+95
| | | | | | | | Two picker-cache bugs from the config audit, verified against current code first. The cache docstring promised clearing on signel-stop, but nothing cleared it, so a stale contact list survived a relink or reconnect. I advised a named clear function :after signel-stop, which makes the docstring true. An empty listContacts result cached nil, indistinguishable from a cold cache, so a zero-contact account re-ran the picker's blocking fetch (up to the 3s timeout) on every open. The fetch now caches an empty sentinel and the picker reads through cj/signel--cached-contacts. One existing test pinned the nil behavior and now asserts the sentinel instead.
* feat(ai-term): pick the agent runtime at session launchCraig Jennings27 hours4-10/+255
| | | | | | | | | | A fresh agent session now asks which runtime to run: claude, codex, or any local ollama model via codex --oss. RET keeps claude, so the common launch stays Enter-Enter. Reattaches and redisplays never ask. The picker fires only when neither a live agent buffer nor a surviving tmux session exists. I mirrored the runtime names and launch strings from the bin/ai launcher so the two stay one mental model, and the choice list itself comes from "ai --print-runtimes" when that launcher is installed, reusing its live ollama scan and dead-server timeout. A static claude-first list stands in without it. The explicit --local-provider=ollama flag is deliberate: configuring the provider through config.toml silently does nothing. The chosen command threads through show-or-create into the tmux launch line. On reattach, tmux new-session -A ignores it, so no reattach path changes behavior. cj/ai-term-agent-command keeps its meaning as the claude runtime's full line. Thirteen tests cover the runtime-to-command map, the print-runtimes parsing, the launcher fallback, and the launch-command override.
* refactor(mu4e-contacts): drop no-op completion hook surgeryCraig Jennings27 hours1-8/+9
| | | | mu4e 1.14 calls mu4e--compose-setup-completion directly during compose setup, never via mu4e-compose-mode-hook, so the activate path's remove-hook did nothing and the deactivate path's add-hook installed a function that was never hook-driven. The mu4e-compose-complete-addresses variable already gates the built-in completion on both paths. I also declared that variable for the compiler, which clears the module's two free-variable warnings.
* fix(mu4e-attachments): reject stale MIME handles at save timeCraig Jennings27 hours2-1/+61
| | | | | | The selection buffer captures MIME handles when it opens, but viewing another message kills the buffer a handle points at. Saving through such a handle died deep in mm-decode, or could write another message's bytes. The save path now signals a user-error naming the attachment when its handle's buffer is dead, and it checks before any mu4e MIME support loads, in the same spot as the existing no-handle check. I added tests for the stale-handle error, the healthy live-handle save, and the mid-batch failure behavior (the error propagates and files already written stay).
* fix(mail): repair account nav, send fallback, and reply handlingCraig Jennings28 hours3-52/+92
| | | | | | | | | | | | | | Seven config-audit findings in mail-config, each verified against the installed mu4e 1.14 source before changing anything: - The C-; e account nav commands now require mu4e before searching. The maps register eagerly at startup, but mu4e-search has no autoload cookie, so a nav key pressed before mu4e's first launch signaled void-function. - With msmtp absent, both send variables now get cj/mail--send-mail-unavailable, which signals a user-error naming msmtp. The old fallback left message-send-mail-function nil (the top-level defvar pre-empts message.el's default), so the first send died with "invalid function: nil". - I removed the unconditional org-msg-edit-mode advice on the two reply commands. org-msg-post-setup already runs on mu4e-compose-mode-hook and applies org-msg-default-alternatives itself, so the advice forced org-msg onto text-only replies and re-ran a major mode org-msg had already set up. - I dropped the save-attachment headers action: mu4e-view-save-attachments takes no message argument and reads MIME parts from the view buffer, so it never worked from headers. - I deleted the obsolete HTML view knobs (mu4e-view-prefer-html and both mu4e-html2text-command sets): the shr-based view has ignored them since mu4e 1.7. - I reordered the contexts so cjennings.net comes first: with pick-first, gmail-first made gmail the silent default account for the first compose. - I dropped mu4e-starred-folder (not a mu4e variable, never had an effect) and the obsolete mu4e-maildir alias. New tests cover the nav-command mu4e load and the msmtp-absent fallback.
* chore(org-capture): clear the module's byte-compile warningsCraig Jennings34 hours1-7/+7
| | | | | | I removed the remove-hook shim that swapped the retired popup handler out of a live daemon on module reload. The handler it names was deleted long ago and both daemons have restarted since, so the shim's only remaining effect was a not-known-to-be-defined warning. I also declared org-capture-mode-map for the compiler (it's only ever touched inside with-eval-after-load) and reflowed one over-wide docstring. The module now byte-compiles with zero warnings.
* test(org-capture): cover the popup neutralize guardsCraig Jennings34 hours1-0/+136
| | | | | | The guards from the previous commit landed without tests. I added ten: eviction of a stray live buffer to *scratch*, capture UI spared (*Org Select*, CAPTURE-*), idempotence on a window already showing *scratch*, non-popup frames untouched, nil and non-frame inputs ignored, both hook wrappers' dispatch, and hook registration. The tests drive the real batch frame instead of mocking frame primitives: they rename it to "org-capture", exercise the guard, and revert to auto-naming. The revert must be nil, not the saved name, because Emacs refuses to set F<num>-shaped names explicitly. window-buffer-change-functions only runs during redisplay, so the module's own hook can't fire mid-test in batch.
* fix(org-capture): keep the popup frame from clamping a live terminal bufferCraig Jennings34 hours1-0/+49
| | | | | | The capture popup frame opens showing the daemon's last buffer, and only the capture UI or the reap-on-finalize hook clears it. When a capture aborts before its UI paints (a C-g, an erroring template, a path that skips cj/quick-capture), the popup lingers on whatever was current. If that was a live eat/vterm terminal, eat sizes the terminal to the small popup window and clamps the real frame to the popup's rows. Two guards keep the popup from ever holding a size-sensitive live buffer. One on after-make-frame-functions neutralizes the frame at creation, the root cause. One on window-buffer-change-functions catches the abort and stray-switch paths the finalize reap misses. Both repoint any non-capture-UI window to *scratch*, sparing *Org Select* and CAPTURE-* buffers so a live capture is never disturbed.
* feat(eat-config): answer XTWINOPS queries so tmux renders sixel in EATCraig Jennings35 hours2-0/+216
| | | | | | | | tmux 3.7b won't emit sixel until it learns the client's cell pixel size via CSI 14/16/18 t. EAT 0.9.4's parser has no CSI t clause and drops the queries, so images never render. I added a :before advice on eat--t-handle-output that scans the raw output and answers through the terminal's own input function (eat--t-with-env binds eat--t-term). I verified it live: images render and survive window switches, scrolling, and resizing. I guarded the advice-add so it installs only while EAT itself can't answer. Two answerers give tmux a double reply, and it forwards the second one's raw bytes into the pane as keystrokes. The guard keys on eat--t-send-window-size-report, the function an upstream clause would define. I kept an upstream-shaped parser-clause patch locally for a PR to akib/emacs-eat.
* fix(calendar-sync): stop EXDATE scan loop on comma-separated valuesCraig Jennings35 hours1-3/+9
| | | | calendar-sync--get-exdates read (match-end 0) after split-string, whose internal matching clobbers the match data. The scan position jumped back to a comma offset inside the value and re-matched the same EXDATE line forever, growing the result list until the kernel OOM killer took the whole session down (twice, 2026-07-13). The fix captures the line's end position before the split. The comma-separated tests added with a9e61207 were the first code to hit this path. All 12 exdates tests and all 56 calendar-sync test files now pass in milliseconds.
* bug: fixing exdate lines and adding testsCraig Jennings39 hours2-6/+38
|
* fix(org-drill-config): fall back to :vc when the dev checkout is absentCraig Jennings3 days2-19/+67
| | | | org-drill-config hard-coded :load-path to ~/code/org-drill with :demand t, so on a machine without that checkout org-drill failed to load and drill broke. cj/--org-drill-source-keywords now picks the source at load time: :load-path when the checkout exists, a :vc install otherwise. The keyword is spliced through eval, since use-package needs a literal at macro-expansion.
* refactor(org-webclipper): remove dead commented keymap blocksCraig Jennings3 days1-20/+0
|
* refactor(calendar-sync-source): drop dead fetch variant, test the sentinelCraig Jennings3 days2-46/+95
| | | | The buffer-string calendar-sync--fetch-ics had no callers. The sync path uses the temp-file variant exclusively, so 30 lines of curl and sentinel logic that would only drift are gone. I also pulled the fetch-ics-file sentinel's finish logic into calendar-sync--fetch-sentinel-finish so its success, failure, and temp-file-cleanup branches can be tested without a live curl process. The async-worker tests stub the whole fetch and never reached them.
* fix(org-contacts-config): jump to contact heading, not a body matchCraig Jennings3 days2-13/+96
| | | | cj/org-contacts-find visited the contacts file before prompting, so a C-g at the prompt stranded point at the top of it. It then jumped with search-forward, which could land inside another entry's body that mentioned the name. I collect the headings with find-file-noselect first (extracted as cj/--org-contacts-collect), prompt, then jump to the selected heading's stored position. The prompt now requires a match, since a typed non-match has no position to jump to.
* fix(org-reveal-config): register presentation keys via prefix mapCraig Jennings3 days2-11/+60
| | | | The seven presentation commands were bound with raw global-set-key on "C-; p ..." chains. That only works once keybindings.el has made "C-;" a live prefix. Otherwise each binding errors with "non-prefix key". I replaced them with cj/reveal-map registered under "C-; p" via cj/register-prefix-map, matching every sibling and dropping the load-order dependency.
* fix(flyspell-and-abbrev): stop re-scanning the whole buffer on every C-'Craig Jennings3 days2-3/+26
| | | | cj/flyspell-then-abbrev ran a bare flyspell-buffer guarded by (unless flyspell-mode ...), but nothing turned flyspell-mode on, so the guard never tripped. Every C-' press re-scanned the whole buffer, which is O(buffer) per keypress in large files. I routed the scan through cj/flyspell-on-for-buffer-type instead, so the mode sticks after the first press and the buffer is scanned once.
* fix(lorem-optimum): guard empty chain, make cj/lipsum a commandCraig Jennings3 days2-2/+37
| | | | | | cj/lipsum returned nil when the Markov chain was empty (for example with the training file missing), so cj/lipsum-insert ran (insert nil) and raised a cryptic wrong-type error far from the cause. It now signals a user-error naming the fix: train the chain or restore the file. The Commentary advertised M-x cj/lipsum, but the function had no interactive spec. I added one, echoing the words interactively while still returning the string for cj/lipsum-insert and cj/lipsum-paragraphs.
* fix(keyboard-macros): require user-constants at runtime, drop exit promptCraig Jennings3 days1-10/+2
| | | | | | user-constants was required only at eval-when-compile, but macros-file lives there and every macro-load path reads it at runtime. The byte-compiled module never pulled user-constants, so it worked only because init.el happens to load user-constants first. An isolated load of the .elc left macros-file unbound. Made it a plain require. Dropped cj/save-last-kbd-macro-on-exit and its kill-emacs-hook. On a daemon or systemd shutdown the y-or-n-p and name prompt have no one to answer, and M-<f3> already persists named macros, so unnamed throwaways don't need a shutdown gate.
* fix(text-config): bind edit-indirect and accent to reachable keysCraig Jennings3 days2-3/+16
| | | | | | edit-indirect-region was bound to "M-S-i", but pressing Meta+Shift+i produces the event M-I, not M-S-i. No keypress reached the binding, so it fell through to M-i tab-to-tab-stop. I bound it on "M-I" instead. The "was M-I" comment had it backwards: that earlier rename wasn't a no-op. accent's C-` used accent-company, which needs the company backend. The pending Company-to-Corfu migration doesn't cover accent, so C-` would break silently once company is gone. I switched to accent-menu, which reads through the minibuffer and works regardless of the completion backend.
* refactor(org-export): delete dead ox-texinfo block, relocate footnote settingCraig Jennings3 days2-16/+3
| | | | | | | | | | | | | The ox-texinfo block could never run: :defer t with no autoload trigger, and absent from the dolist that force-requires the other backends. So its :config never fired, and Texinfo export was unavailable despite the commentary advertising it. I deleted the block and dropped the Texinfo line from the commentary. The commentary also claimed subtree default scope while the code sets 'buffer, so I fixed that too. I moved org-html-footnote-separator out of org-babel-config, where it sat as a stray ox-html setting, into ox-html's own :config. ox-html loads before any HTML export reads the value, so the timing is unchanged.
* refactor(org-agenda): move timegrid setting to its owner, drop dead timelineCraig Jennings3 days2-3/+1
| | | | | | | | | | org-agenda-timegrid-use-ampm lived in org-roam's :config, so it only took effect once org-roam loaded at its 1s defer. I moved it into org-agenda's own :config beside the other agenda display settings, and dropped the now-unused defvar from org-roam. I also removed the timeline entry from org-agenda-prefix-format. The timeline agenda type was removed from org in 9.1, so the entry was inert.
* fix(org-roam): resolve void find-node bindings, drop dead configCraig Jennings3 days5-100/+21
| | | | | | | | | | | | | | | | | | | | C-c n p and C-c n w were bound to cj/org-roam-find-node-project and -webclip, which no use-package :bind autoload could fulfill (they point at org-roam, which defines neither), so both keys errored with "autoloading failed to define function". I defined find-node-project as a sibling of find-node-topic/recipe against the existing project.org template, and dropped the webclip binding and label since no webclip template or flow exists. I repointed the v2mom/recipe/topic capture templates from .emacs.d/org-roam-templates/ to roam-dir/templates/ so one canonical directory feeds both the capture templates and the find-node commands. They had drifted, and edits to one copy never reached the other. Deleted the now-redundant .emacs.d/org-roam-templates/ files. I removed the 28-line commented consult-org-roam block. Its proposed C-c n l / C-c n r collide with live bindings, so it couldn't ship as written. Git keeps the draft.
* fix(custom-case): align title-case with its docstring and standard rulesCraig Jennings3 days2-18/+47
| | | | cj/title-case-region contradicted its own docstring in three ways. It lowercased "is" despite the docstring calling linking verbs major words; it never restarted capitalization after a sentence-ending period; and it had no rule to capitalize the last word. I made the code match the standard: dropped "is" from the minor-word skip list, added the period to the reset characters (a period plus a blank restarts, so "3.14" and "foo.bar" are still left alone), and always capitalize the last word by locating its start once. Updated the four characterization tests that asserted the old behavior and added tests for the last-word and period-restart rules.
* fix(custom-text-enclose): decouple indent count from the tabs choiceCraig Jennings3 days2-5/+41
| | | | cj/indent-lines-in-region-or-buffer used "p\nP", so both COUNT and USE-TABS came from the one prefix argument: no prefix gave count 1 (the docstring's "4" was wrong) with spaces, and any numeric prefix that set the count also forced tabs. Indenting several spaces was unreachable interactively. The prefix argument is now the count (defaulting to 4), and tabs-vs-spaces follows the buffer's indent-tabs-mode. cj/dedent-lines-in-region-or-buffer had the same wrong "default 4" and now defaults its count to 4 too. Added interactive-path tests, since the internals were already covered.
* fix(custom-ordering): preserve the trailing newline in reverse and numberCraig Jennings4 days3-17/+35
| | | | cj/reverse-lines and cj/number-lines split the region on newlines without accounting for a trailing one, so it became a spurious empty element. Reversing "a\nb\n" floated that empty to the top ("\nb\na"), and numbering added a phantom final numbered line. Both now strip a trailing newline before splitting and reattach it after, matching cj/--arrayify, while preserving internal blank lines. Corrected the two tests that asserted the broken output.
* fix(custom-line-paragraph): correct paren-jump, line-join, and duplicateCraig Jennings4 days4-35/+102
| | | | | | | | | | This module carried three editing bugs. cj/jump-to-matching-paren, with point on a closing delimiter, ran backward-sexp from there and landed on the last inner sexp instead of the opener. It now steps past the closer first so backward-sexp spans the whole expression, and restores point when the delimiter is unmatched. Four tests that asserted the last-inner-sexp landings are corrected to the true matching opener. cj/join-line-or-region, without a region, added a newline unconditionally after joining, which left a stray blank line when joining a line in the middle of the buffer. It now adds the newline only at end of buffer. cj/duplicate-line-or-region duplicated a stray empty line for a region ending at beginning-of-line and split the line for a region ending mid-line. I normalized the bounds to the whole lines the region touches and insert that block once.
* fix(custom-comments): correct comment-reformat and inline-borderCraig Jennings4 days3-25/+34
| | | | | | cj/comment-reformat printed "No region was selected" on every call, even successful ones, because the message sat outside the if. Its fill-column shrink used a raw setq and restore, so an error mid-join left fill-column permanently at -3. It now signals a user-error when there's no region and dynamically binds fill-column, which restores itself. cj/--comment-inline-border sized the right decoration from text-length parity, leaving even-length and empty text two columns short and misaligning stacked dividers. It now fills the exact remaining width. Both fixes ship with tests, and the inline-border test asserts exact width across parities.
* fix(custom-datetime): make sortable-time actually sortableCraig Jennings4 days2-3/+4
| | | | sortable-time-format was 12-hour with AM/PM ("%I:%M:%S %p %Z"), so "01:00:00 PM" sorted before "09:00:00 AM". I switched it to 24-hour "%H:%M:%S %Z", matching sortable-date-time, and updated the test that asserted the AM/PM output.
* fix(custom-buffer-file): error when copy-link has no file to copyCraig Jennings4 days2-10/+14
| | | | cj/copy-link-to-buffer-file did nothing in a non-file buffer, while every sibling copy command signals a user-error. The silent no-op gave no feedback either way. Now it signals a user-error too, and I updated the two tests and the commentary that had documented the silence as intended.
* refactor(selection-framework): drop the overridden vertico sort customCraig Jennings4 days1-1/+3
| | | | vertico-sort-function was set to history-alpha, but vertico-prescient-mode owns sorting inside every vertico session and overrode it, so the custom never took effect. I removed it (leaving a note) and kept prescient's frecency sorting, which is the intended behavior.
* refactor: retire unreferenced modules to an archive directoryCraig Jennings4 days12-8/+73
| | | | | | A reachability sweep from init.el found eight .el files that nothing in the config loads or references. I moved them under archive/ (off the load-path, still tracked in git) so they stay readable and restorable rather than deleted. archive/README.org records the rule (every .el outside archive/ should be actively used) and why each file was retired. I retired show-kill-ring, duet-config, and mu4e-org-contacts-setup from modules/, and eplot, profile-dotemacs, titlecase, titlecase-data, and edit-indirect from custom/. Retiring show-kill-ring also removed the orphaned M-K -> M-S-k translation in keyboard-compat, which had left M-K a dead key. Its tests now assert seventeen translations and guard M-K's absence.
* fix(custom-buffer-file): stop leaking the MIME handle in the email viewerCraig Jennings4 days2-15/+45
| | | | | | cj/view-email-in-buffer dissected the message into a handle, then signaled a user-error when it found no displayable part, before the mm-destroy-parts cleanup. The handle leaked on every image-only or attachment-only email. Wrap the body in unwind-protect so the handle is always destroyed. While here, the eager top-level require of mm-decode only fed the mm-handle-type macro at compile time. The viewer already requires mm-decode at runtime before any mm-* call, so I moved it to eval-when-compile plus declare-function (matching the ps-print block above). Opening Emacs no longer loads mm-decode unless you view an email.
* refactor(ui-config): drop the duplicate nerd-icons stanzaCraig Jennings4 days1-9/+0
| | | | nerd-icons is owned by nerd-icons-config.el (:demand t, plus the dir-color advice and the completion and ibuffer integration). This bare :defer t re-declaration did nothing, so I removed it and its Commentary bullet.
* fix(ui-theme): create persist/ before writing the saved themeCraig Jennings4 days2-2/+21
| | | | cj/theme-write-file-contents guarded on file-writable-p, which returns nil when the target's directory doesn't exist. On a fresh machine persist/ isn't there yet, so the theme write failed silently and the choice never persisted. Create the parent directory first, and still return nil if the path isn't writable.
* fix(undead-buffers): guard kill-other-window against a lone windowCraig Jennings4 days2-8/+15
| | | | | | | | In a single-window frame cj/kill-other-window killed the buffer being viewed: other-window no-ops, delete-window was guarded, but the kill still ran on the current buffer. Signal a user-error instead, matching the sibling cj/kill-other-window-buffer. Past the guard there's always another window, so delete-window drops its own check. The single-window test asserted the broken behavior, so I rewrote it to expect the user-error and an untouched buffer. Also documented the prefix-argument undead-mark in cj/kill-buffer-or-bury-alive.
* fix(font-config): daemon emoji images and a re-runnable font listCraig Jennings4 days2-16/+74
| | | | | | emojify-display-style was computed once from env-gui-p inside the :defer'd :config block. In a daemon that block runs before any GUI frame exists, so the style latched to unicode and GUI frames never got image emoji. Recompute it per-frame from server-after-make-frame-hook, mirroring the emoji-fontset setup above. cj/display-available-fonts called special-mode at the end, leaving the buffer read-only, so the second invocation errored on erase-buffer. Rewrite it under inhibit-read-only.
* feat: add takuzu-config and wire it into initCraig Jennings4 days2-0/+18
| | | | | | Wire the standalone Takuzu (Binairo) game with use-package and require it at startup so M-x takuzu is available. The package lives in its own repo and loads by :load-path. Switch to :vc once it is published.
* refactor(local-repository): drop the dead archive-init pathCraig Jennings4 days3-111/+41
| | | | localrepo-initialize, localrepo--car-member, and the repository-id/priority defcustoms were never called: early-init.el owns adding the local archive to package-archives, with its own localrepo-location constant. The module is now just cj/update-localrepo-repository. It targets localrepo-location, so there's one archive path instead of a divergent copy. The car-member test goes with its subject. A new test pins that the mirror update uses localrepo-location.
* refactor(keybindings): drop the no-op C-x C-f rebindCraig Jennings4 days1-2/+0
|
* fix(system-utils): correct swapped args in the run-on-file messageCraig Jennings4 days1-1/+1
|