| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
| |
cj/make-script-executable runs from a global after-save-hook and set +x on any saved file whose first line was a shebang, in every buffer. A downloaded script you were reading, a template, or a shebang in a text or org file silently became executable. I gated it on derived-mode-p prog-mode, so it only acts on actual script buffers. Real scripts (sh-mode, python-mode) still get the fast path.
|
| |
|
|
|
|
| |
The live markdown preview pulled strapdown.js from http://ndossougbe.github.io over plain HTTP. That broke the preview with no network, loaded third-party JS over an unencrypted connection (mixed content, MITM), and trusted an unmaintained github.io page against the localhost preview.
I vendored the self-contained bundle (jQuery, marked, bootstrap themes) into assets/strapdown.js and embed it inline. The whole preview now serves from localhost and works offline. cj/markdown-html reads the file once and caches it.
|
| | |
|
| |
|
|
|
|
|
|
| |
Emacs crashed at launch with wrong-number-of-arguments on cj/save-some-buffers, down the startup path (dashboard-only to kill-all-other-buffers to save). Two modules defined a function by that name: custom-buffer-file.el's legible save prompt (arg + pred), installed as an override on save-some-buffers, and undead-buffers.el's older one-arg wrapper that called save-some-buffers internally. custom-buffer-file loads first, undead-buffers second. The one-arg version won the shared symbol, so the override re-entered it with two args.
I removed undead-buffers.el's wrapper. cj/kill-all-other-buffers-and-windows now calls the standard save-some-buffers with the undead predicate, which routes through the override when loaded and the built-in otherwise, so undead-buffers no longer depends on custom-buffer-file. The legible override keeps the cj/save-some-buffers name.
A regression test loads both modules in launch order and guards the call and the arity so a one-arg shadow can't return.
|
| |
|
|
|
|
| |
Declining one occurrence of a recurring meeting left it on the agenda. Google emits that decline as a RECURRENCE-ID override carrying the user's PARTSTAT=DECLINED. But calendar-sync--parse-exception-event never read the override's attendee block, so the occurrence kept the series' inherited "accepted" status and the declined filter never dropped it. The apply side already re-derives status from an override's attendees. The parse side just wasn't supplying them.
The fix parses the override's ATTENDEE lines into :attendees, the same way parse-event does. A unit test covers the extraction. An integration test runs the full parse/apply/filter chain on a declined week.
|
| |
|
|
|
|
| |
Add the font-lock faces the syntax tier didn't cover (warning, doc-markup, negation-char, and the two regexp-grouping faces) as their own editable categories: warn, dmark, neg, rxgb, rxgc. Each maps 1:1 to its face, seeds from the stock defaults, and is exercised in the code-sample preview via a TODO comment, a docstring substitution, a string regexp, and a C negation.
Injected only the five new faces into the default-faces snapshot rather than regenerating it wholesale. A full recapture pulls in unrelated package-inventory drift.
|
| | |
|
| |
|
|
| |
Pull the long-term subr-mock migration out of the task list into a discussion spec: the native-comp origin, the stopgap already shipped (variadic sweep plus the arity meta-test), the real scope (the UI-prompt mocks, not the boundary mocks the test rules say to keep), and the open decisions to settle before any code moves.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
disk-changed saves
Replace the cryptic single-key save prompts with read-multiple-choice menus whose options are labeled on screen instead of recalled as keys.
save-some-buffers (C-x s and save-on-exit) is overridden with a reimplementation that reuses the stock candidate selection and abbrev-save tail but swaps map-y-or-n-p's terse key list for a labeled menu, and adds a clean-whitespace-and-save action.
C-x C-s gains a wrapper that fast-paths normal saves to save-buffer; only when the buffer has unsaved edits and the file changed on disk does it show a labeled menu (save / diff / clean / revert / cancel) instead of the bare "Save anyway?" yes/no.
Both menus share a diff toggle, and whitespace-only diffs route to a plain unified diff with trailing whitespace highlighted, since difftastic normalizes trailing whitespace and renders such changes blank.
The interactive wrappers stay thin over pure, tested helpers: the save-loop planner, the key-to-action maps, the whitespace detector, and the renderer choice.
|
| | |
|
| |
|
|
| |
The nov reading view app gains six faces: a heading and link accent for each of the sepia, dark, and light palettes, seeded to match the module defaults. The book-page preview now draws each page's title in its palette's heading face and an inline phrase in its link face, iterating only the base palette faces so the structural faces color a page rather than getting blank pages of their own.
|
| |
|
|
|
|
| |
Font size now carries across books and sessions. The +/-/= keys write the text-scale offset to data/nov-reading-text-scale and the offset is restored when a book opens, so a size I set sticks instead of resetting to the base height on every reopen. The = key returns to the base height and persists that reset.
Each palette grows from a single bg/fg face into a bundle: :face plus optional :heading and :link. When a palette is active, its heading and link faces remap shr's h1-h6 and link faces buffer-local, so the EPUB hierarchy reads in the palette's accent. The remap stays buffer-local to the nov buffer, so HTML mail and eww keep the theme's normal shr colors.
|
| |
|
|
| |
The nov-reading app fell back to the generic preview (face names in their own colors), which doesn't show what a palette looks like. I added a renderer that draws a real book page per palette: a mock page of Hawthorne's "Dr. Heidegger's Experiment" in sepia, dark, and light, with a small-caps byline, a drop cap, and justified serif prose. Each page takes its background and foreground from its palette face, so tuning a palette repaints its page.
|
| |
|
|
|
|
|
|
| |
EPUB reading prefs were scattered: a hardcoded Merriweather/180 font-remap in calibredb-epub-config's nov hook, no color control (the old sepia foreground had been stripped), and a frame-global EBook fontaine preset as the only way to size up. That preset resized the font in every buffer in the frame, not just the book.
I pulled the reading view into its own layer, modules/nov-reading.el, on top of stock nov (no fork). It owns three things, all buffer-local: a reading palette (sepia/dark/light, each a face the dupre theme owns, sepia the default), the serif typography (family plus a defcustom base height replacing the hardcoded 180), and page font sizing (+/- bump the size live, = resets to the base). Width moves to { }. calibredb-epub-config keeps the library and width/centering layout. Its nov hook now calls into the layer.
The three palette faces register as a nov-reading app in theme-studio (face_data.py), so they're tunable there like any other app. I dropped the EBook fontaine preset, since reading size is buffer-local now.
|
| |
|
|
|
|
| |
calendar-sync ran calendar-sync-start at load, which syncs immediately and then every interval. Every configured calendar resolves its .ics feed URL from a :secret-host in authinfo.gpg, so both the immediate sync and each timer tick decrypt authinfo.gpg. On a cold gpg-agent (after a reboot) that surfaced as a GPG passphrase prompt right after startup, before I'd asked for anything needing a secret.
I deferred the whole start, immediate sync and recurring timer alike, to the first org-agenda use via a one-shot org-agenda-mode-hook. The unlock now happens when I actually open the agenda. A manual calendar-sync-start or calendar-sync-now still works on demand.
|
| |
|
|
| |
nerd-icons already rendered every icon in the config (dashboard, dirvish, ibuffer, completion). all-the-icons survived only as scaffolding: a font-install helper, the all-the-icons-nerd-fonts bridge, and a terminal-blanking advice block the nerd-icons one beside it already duplicated. I removed all of it and pointed the font-install helper at nerd-icons (Symbols Nerd Font Mono), keeping the auto-install-on-first-GUI-frame convenience. I updated the font-config tests to the renamed helper.
|
| |
|
|
| |
Inside EAT terminals C-<backspace> did nothing: terminals send no standard code for it, so EAT forwarded a bare key the program dropped. I bound it in eat-semi-char-mode-map to send M-DEL (ESC DEL) to the pty, which readline maps to backward-kill-word. That's the same word-boundary delete C-<backspace> does in normal buffers.
|
| |
|
|
| |
F1 (cj/dashboard-only, the kill-all sweep back to the dashboard) was swallowed by the pty inside agent EAT buffers. EAT forwards unbound keys to the terminal, so I bound F1 in eat-semi-char-mode-map and eat-mode-map alongside the existing F12 and C-; passthroughs. Unlike ghostel, EAT needs no exception-list or keymap rebuild.
|
| |
|
|
|
|
|
|
|
|
| |
The Super+N quick-capture popup frame is named "org-capture" and was torn
down by deleting the selected frame on capture exit. When the daemon's
selected frame was something else at finalize (common with multiple frames),
the real capture frame survived and lingered, showing whatever buffer was
behind it. Reap by frame name across all frames instead, sparing any popup
still mid-capture (*Org Select* or a CAPTURE-* buffer), and expose
cj/org-capture-reap-popup-frames for manual cleanup.
|
| | |
|
| |
|
|
|
|
|
|
|
| |
make task-sorted now ages the Resolved section. Tasks closed more than a
week ago, and any with no CLOSED date, move out to archive/task-archive.org,
keeping only the last week of closed tasks in todo.org. The target then runs
org-lint on todo.org to catch structural problems from the move. This pass
moved 207 tasks to the archive and pulled 4 newly-closed tasks into Resolved,
dropping todo.org from 9,600 to 5,600 lines.
|
| |
|
|
|
|
|
|
|
|
| |
Eight completing-read pickers listed bare file basenames, so marginalia had no directory to resolve and couldn't annotate them. Add cj/completion-file-annotator to system-lib — an annotation-function factory that takes a candidate->path resolver and yields a size + modification-date suffix (or "dir" for directories, nil for missing files). Wire each picker through cj/completion-table-annotated with a per-site category and resolver: timer sounds, drill flashcards, Info files, the test-runner focus add/remove, vc clone dirs, hugo drafts, and agenda projects (the project's todo.org mtime). music-config's existing completion table gains the category and annotator inline, keeping its sort metadata.
The candidate strings and every return value are unchanged — this only adds completion metadata — so all downstream logic is untouched. The six modules that didn't already pull in system-lib now require it.
Tests: cj/completion-file-annotator gets Normal/Boundary/Error coverage (file, directory, nil path, missing file). Full suite green at 5394.
Claude-Session: https://claude.ai/code/session_014fyKMTTqLrZpL3rDF3dYc3
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Break the 1025-line video-audio-recording.el into a thin public face plus two layered libraries, moving every function verbatim so behavior and public names are unchanged:
- video-audio-recording-devices.el — base layer: PulseAudio source and sink discovery, the pactl output parsers, device labeling and sort/status helpers for completing-read, and the lookup predicates. Pure string and shell-query helpers with no dependency on recording state, config, or the engine. This is the heavily-tested core.
- video-audio-recording-capture.el — engine: ffmpeg/wf-recorder command construction, the recording process lifecycle (sentinel, producer-first shutdown, exit polling), the modeline indicator, dependency checks, device acquisition and validation, and the start/stop entry points. Requires the devices layer.
video-audio-recording.el keeps configuration and the recording process-handle state, the device-diagnostic and device-test commands, the toggle commands, and the C-; r keymap, and requires the two layers. The engine reads and updates the config and process-handle variables, which the top module owns, through forward declarations, so no layer requires the top module back. No function call crosses from a layer up into the top module, so the split needs no forward-declared functions.
Every public name is preserved, so all 323 existing video-audio-recording tests pass unchanged through the require chain. The two new modules carry the load-graph and package headers and join the header-contract allowlist.
Claude-Session: https://claude.ai/code/session_014fyKMTTqLrZpL3rDF3dYc3
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Break the 1724-line calendar-sync.el into a thin public face plus four layered libraries, moving every function verbatim so behavior and public names are unchanged:
- calendar-sync-ics.el — base parsing: RFC 5545 text cleaning, VEVENT property extraction, attendee/organizer/URL parsing, timezone and timestamp conversion, date arithmetic, single-event parsing. Depends on neither of the other new modules.
- calendar-sync-recurrence.el — RRULE/EXDATE/RECURRENCE-ID expansion.
- calendar-sync-org.el — Org rendering and atomic file output.
- calendar-sync-source.el — sync state and persistence, async .ics fetch, the batch conversion worker, and the Google Calendar API path.
calendar-sync.el keeps configuration, the parse orchestrator, sync dispatch, the user commands, the timer, and the C-; g keymap, and requires the four layers. Each layer forward-declares the config defvars it reads, so no layer requires the top module back. The batch worker loads the whole graph, so source forward-declares the two functions it calls there.
Every public name is preserved, so all 574 existing calendar-sync tests pass unchanged through the require chain. The four new modules carry the load-graph and package headers and join the header-contract allowlist.
Claude-Session: https://claude.ai/code/session_014fyKMTTqLrZpL3rDF3dYc3
|
| |
|
|
|
|
| |
test-system-cmd-restart-emacs-no-service-aborts mocked cj/system-cmd--emacs-service-available-p directly, but cj/system-cmd-restart-emacs reaches that helper through a native-comp intra-file direct call that bypasses the symbol-function redefinition. The mock silently no-opped, the real check ran, and on any machine that has emacs.service it returned non-nil, so restart proceeded and the should-error saw no error.
I mock executable-find to nil instead, driving the real helper to nil at a boundary its subr trampoline honors, matching the passing sibling tests. The test now passes whether or not emacs.service is installed.
|
| |
|
|
|
|
| |
custom-misc.el was an incoherent grab-bag, so anything small defaulted to landing there. I split its eight commands by concern. Three moved into new modules: custom-format (region/buffer reformat), custom-counts (word and character counts), and custom-text-transform (fraction glyphs). The other three went to existing homes: the previous-buffer toggle to custom-buffer-file, the delimiter jump to custom-line-paragraph, and the align-regexp space advice with its alignment and fill bindings to custom-whitespace.
The C-; bindings, which-key labels, and the six test files moved with their functions, and custom-misc.el is deleted. No behavior change: every command keeps its name and its C-; key.
|
| |
|
|
|
|
| |
Two owned helpers carried unprefixed generic names that risk colliding in the single Emacs namespace: car-member (local-repository.el) and unpropertize-kill-ring (system-defaults.el). I renamed them to localrepo--car-member and cj/--unpropertize-kill-ring and updated their callers and tests. Both are non-interactive and contained, so no alias was needed.
docs/design/naming-audit.org records the rest of the scan: the allowlist of deliberate module prefixes, the foreign forward-declarations that aren't owned definitions, and a deferred list (keybound commands, the with-timer macro, the ui-theme defcustoms, the user-constants paths) that each want a focused pass rather than an unattended rename.
|
| |
|
|
|
|
| |
The first-line header on 33 modules named the file without its .el extension (;;; font-config --- ... rather than ;;; font-config.el --- ...), the form checkdoc and package-lint expect and the other modules already use. I normalized all 33 to the canonical ;;; name.el --- summary shape. The change is line 1 only.
A new test, test-meta-package-headers.el, locks the convention. It checks every module for the canonical first line, Commentary before Code, a provide footer, and no BOM, and unit-tests the checker against each malformed shape so the guard itself is proven.
|
| | |
|
| |
|
|
| |
The route-colors pass dropped the literal cj/music-* face definitions but left the playlist header referencing them, so every header render spammed "Invalid face reference". I restored the five as deffaces that inherit themed base faces, so the theme still owns their colors. A test asserts each referenced face is defined.
|
| |
|
|
|
|
| |
F1 (cj/dashboard-only) kills every other buffer, burying only those on the undead list. Agent buffers were never registered, so the sweep killed live agents and detached their sessions.
Agent buffers are a dynamic family ("agent [<project>]") that an exact-name list can't pre-enumerate, so undead-buffers gains a regexp list (cj/undead-buffer-regexps) and a centralized cj/--buffer-undead-p predicate. Both kill paths route through it. ai-term registers the "agent [" pattern, so every agent -- current or future, however created -- is buried rather than killed.
|
| |
|
|
|
|
| |
Every calibredb launch (the dashboard "b", M-x, anywhere) now opens filtered to the in-progress books rather than the whole library, via an :after advice on calibredb. Clear with L or x to see everything.
The filter scopes to the tag field (calibredb-tag-filter-p), not a bare keyword search. A bare keyword matches any field, which surfaced books that only mention "in-progress" in their description.
|
| |
|
|
|
|
| |
Bookmark reformatting to "Author, Title" was nov-only, so PDF bookmarks kept the raw filename. PDFs open in pdf-view-mode, whose pdf-view-bookmark-make-record carried no advice.
I added a parallel :filter-return advice there, reusing the same extension-agnostic filename parser, and renamed the helpers off the nov- prefix to reading- since they now serve both EPUB and PDF. New tests cover a PDF filename and a PDF-shaped record.
|
| |
|
|
|
|
| |
A Weather launcher joins the dashboard's top row after Agenda, on key w, drawn with the nf-weather-day_sunny_overcast Weather Icons glyph. It opens the wttrin forecast through call-interactively so wttrin's location prompt runs. A bare (wttrin) call errors, since the command takes the location as a required argument that its interactive form supplies.
Row sizes move from 4-4-3-3 to 5-4-3-3. The launcher table stays the single source for both the navigator icons and the keymap.
|
| |
|
|
|
|
| |
Summoning the agent (M-SPC) into a single-window frame docked it at the default fraction even when it was last fullscreen, because the size-memory model only captured split geometry at toggle-off and a sole window has no dock size to record. A window-configuration-change-hook tracker now records whether the displayed agent fills its frame (cj/--ai-term-last-fullscreen), and display-saved restores it in place when that flag and a single-window frame both hold.
The tracker records only that flag, not dock geometry: re-capturing the dock size on every window change fed a capture/replay loop that drifted the dock height a couple rows per cycle. The restore guard uses (one-window-p t) so an active minibuffer (a picker prompt mid-summon) isn't counted as a second window, which otherwise misfired the restore into a dock and cascaded.
|
| |
|
|
|
|
| |
M-<arrow> now mirrors C-; b <arrow>. From a sole window it pulls a sliver split open on the opposite edge, revealing the previous buffer. In a multi-window layout it nudges the divider via windsize.
cj/window-resize-sticky derives the arrow with event-basic-type, so one command serves both chords. M-up/down were unbound, and M-left/right shed word-motion, which stays on C-left/right. org and other modes that own M-arrow still shadow it, so C-; b remains the universal binding.
|
| |
|
|
| |
URL bookmarks have no filename, so dashboard's filename-based per-item icon left them bare next to file bookmarks. Rather than special-case a URL glyph, I dropped per-item icons from the recents, bookmarks, and projects lists (dashboard-set-file-icons nil). The section-heading icons and the launcher row keep theirs.
|
| |
|
|
| |
Load wttrin via :load-path from the local checkout instead of package-vc, so edits in the checkout are testable without a pull. The wttrin-auto-fit-font defcustom exists on release/0.4.0, so the placeholder setq becomes setopt, which also drops the byte-compile free-variable warning the setq carried. The :vc block stays as a commented fallback for production tracking.
|
| |
|
|
| |
wttrin loads from an unversioned local checkout (elpa/wttrin/), which the inventory regex already learned to capture (ffa458a6). This long-lived daemon's wttrin face attribution was scrambled by the session's theme reloading, so rather than regenerate the whole inventory from a disturbed daemon I added wttrin's four file-loaded faces from a clean batch load and regenerated the studio. wttrin is now a previewable app, and all studio gates stay green.
|
| |
|
|
| |
Condensed early-init's debug-flags note and added a why for the deferred global-font-lock, rewrote three vcf-conversion-helpers comments to name the real intent (keeping the reverse-order-to-preserve-positions rationale), and gave the archived testutil-filesystem a real summary while deleting its line-by-line narration comments.
|
| |
|
|
| |
Dead vendored code for reboxing C block comments (1991). Nothing requires or loads it, it has no provide footer, and none of its commands are bound or called. Removing the orphan.
|
| |
|
|
| |
The theme-studio and browser-choice generators now stamp their output with a header that names the authoritative source and says to regenerate rather than hand-edit. I regenerated both files to match. I also deleted six obvious "describe the next form" comments, replaced two stale placeholders in titlecase.el and an incomplete FIXME in org-checklist.el with real rationale, and condensed early-init's header and Commentary.
|
| |
|
|
| |
More of the commentary/comment audit. The custom-* command modules, weather-config, and mousetrap-mode had empty package summary lines and verbose summary paragraphs. I filled the summaries and condensed the prose while keeping each module's load-contract metadata. dwim-shell-config and auth-config had malformed ;; headers (now ;;;), local-repository had a leading BOM, and two test files had blank summaries.
|
| |
|
|
| |
22 module headers carried long user-manual commentaries (quick-starts, keybinding matrices, setup walkthroughs) that belong in user docs, not source. Each now states the purpose, load contract, and entry points tersely. ai-term also drops its stale F9 keybinding references (the scheme is C-; a plus M-SPC now) and a header line claiming a vertical-split that's really host-aware.
|
| |
|
|
| |
C-; ! was a prefix map with per-command leaf keys (s/r/e/l/L/E/S) I rarely use. I bound C-; ! directly to the completing-read menu instead and removed the leaf keys, reclaiming the real-estate. Every command stays reachable through the menu. Updated the commentary and the two keymap tests to the new contract.
|
| |
|
|
| |
I set wttrin-auto-fit-font so the weather font scales to the window width, clamped to wttrin's min/max floor and cap. The option lands when the wttrin package gains the defcustom. Until then it's a harmless no-op the old code ignores, and the later defcustom won't clobber it.
|
| |
|
|
|
|
| |
The added and removed line backgrounds in Claude Code diffs read too bright. I added eat-term-color-22 (added green) and eat-term-color-52 (removed red) to the WIP theme at about half their former brightness: #005F00 to #002f00, #5F0000 to #2f0000. EAT uses each face's foreground as the palette value for both text and background paint, so darkening the foreground darkens the diff background.
The green index is confirmed. The red is the symmetric counterpart. The brighter within-line word-highlight shades are different indices, left until I sample them live.
|
| |
|
|
|
|
| |
make-process :stderr was a file path, but :stderr takes a buffer, so Emacs made a buffer named after the path instead of writing the file. The "Errored. Logs in <file>" notification pointed at a log with no error text, and that hidden buffer leaked one per transcription.
I now route stderr through an explicit, erased buffer: passed to :stderr, threaded to the sentinel, drained into the log, then killed. That keeps stderr off the stdout :buffer, so the transcript stays clean.
|
| |
|
|
| |
build-inventory.el grouped faces by their defining file and pulled the package name only from versioned directories (/elpa/PKG-VERSION/). Locally-developed packages live in unversioned directories (/elpa/PKG/), so every one of them was silently excluded from the studio. Make the version suffix optional so unversioned checkouts are captured too. Verified against a clean wttrin load: wttrin-key resolves to /elpa/wttrin/wttrin.elc and the regex extracts "wttrin". The inventory itself needs regenerating in a clean Emacs to pick these up.
|
| |
|
|
| |
In eat-semi-char-mode, C-- was bound to eat-self-input and forwarded to the terminal, so it never reached text-scale-decrease and the font could only grow. A session climbed to text-scale 17 (~20x, unreadable) with no in-buffer way down. Bind C-- to text-scale-decrease and C-0 to a reset helper. C-= and C-+ already passed through. Low cost: the terminal program and tmux don't use Ctrl+-, and C-0 shadows digit-argument inside eat buffers only.
|