| Commit message (Collapse) | Author | Age | Files | 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
|
| |
|
|
|
|
| |
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.
|
| |
|
|
| |
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.
|
| |
|
|
|
|
| |
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.
|
| |
|
|
| |
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.
|
| |
|
|
| |
The cj/--nerd-icons-color-dir advice forces nerd-icons-yellow onto every dir icon, which wins over nerd-icons-completion's inherit-behind dir face, so setting nerd-icons-completion-dir-face had no visible effect and folders just followed nerd-icons-yellow. Redefine the file-category completion icon to copy the dir icon and prepend nerd-icons-completion-dir-face so it takes the foreground. The copy keeps nerd-icons' memoized original untouched, so dired and dirvish folders are unaffected. Now completing-read folders carry their own color while file icons keep their type face.
|
| |
|
|
| |
ibuffer paints its rows with manual nerd-icons and ibuffer faces, and global font-lock was leaking font-lock-keyword-face onto the buffer and mode names. Exclude ibuffer-mode, the same fix as the shr-rendered reader modes. An empirical scan confirmed plain tabulated-list listings like package-menu and Buffer-menu survive font-lock untouched, so this is scoped to ibuffer, whose content trips keyword fontification.
|
| |
|
|
| |
eww and nov both render with shr, which paints buffers with manual face properties, and global font-lock was overwriting them with syntactic string fontification, the same bug just fixed for elfeed. An audit of live buffers caught nov directly (two open epub buffers, faces clobbered). eww has font-lock-defaults nil too and is the same shr-rendered pattern as the already-excluded elfeed-show and mu4e-view, so I excluded it alongside. The *sdcv* dictionary buffer has its own font-lock-defaults, so its font-lock is by design and left alone.
|
| |
|
|
| |
elfeed paints its search and entry buffers with manual face properties, the date, title, feed, and tag faces the theme styles. Left in global-font-lock-mode the buffer also got syntactic fontification, which overwrote those with font-lock-string-face, so it lost every theme color. Exclude elfeed-search-mode and elfeed-show-mode through cj/exclude-from-global-font-lock, the same fix dashboard and mu4e already use.
|
| |
|
|
| |
Two pickers have bare-name candidates worth a category: the Signal recipient picker, where a name maps to a phone or UUID, and org-contacts find, where a name maps to an email. I tag each with a custom category and a table annotation-function that shows the looked-up value. marginalia has no annotator for these custom categories, so it leaves the table's annotation in place. The other Tier-2 candidates from the survey (ai-term projects, the mu4e contact list) already carry their info inline, so a category adds nothing and I left them bare.
|
| |
|
|
| |
Add cj/completion-table (and an annotated variant) to system-lib: a wrapper that tags any collection with a completion category so marginalia, embark, consult, and sorting can recognize the candidates. None of the config's completing-reads declared a category, so the rich-candidate pickers showed bare. This applies it to the four whose candidates match a standard category and so need no custom annotator: benchmark-method (function), ERC buffer switch (buffer), ai-term close (buffer), and theme switch (theme). Each now annotates for free.
|
| |
|
|
| |
The subprocess player I just switched to dropped in-track seek. I re-added it without the startup fragility that made the IPC player unreliable. mpv still plays the track as a direct argument, so the reliable start is untouched, and --input-ipc-server opens a control socket that only carries seek commands to the already-playing process. f and b seek by cj/music-seek-seconds (default 5). The socket send is a no-op when nothing is playing, so it never errors.
|
| |
|
|
| |
EMMS drove mpv over an IPC socket, starting it idle and sending loadfile across the socket. That handshake left mpv loaded but never streaming, so playback silently failed and the playing flag never set. I replaced it with a subprocess player that runs mpv with the track as a direct argument, the invocation that plays every time. Pause works in place through process signals, SIGSTOP and SIGCONT. In-track seek is gone, the deliberate trade for reliability. --no-config isolates this mpv from the interactive video setup so the two cannot interfere, and it follows the system default audio sink.
|
| |
|
|
| |
EAT paints its whole palette with manual face text properties. Inside global-font-lock-mode the terminal buffer also got syntactic fontification, so a quoted string in program output (a diff shown by Claude Code) became font-lock-string-face and overrode the foreground EAT had painted. The result was the theme's string green over the green diff-added background, green on green. I excluded eat-mode the same way dashboard and mu4e are, through cj/exclude-from-global-font-lock. A mode-hook can't do it because global font-lock runs after the mode hook.
|
| |
|
|
| |
Claude Code and similar inline TUIs sometimes truncate a colored span without emitting a reset; the unterminated color then bleeds onto every following line in the EAT buffer. Advise eat-term-process-output to inject an SGR reset before each newline, containing the bleed to its own line. Validated in real EAT and via an ansi-color proxy: it contains the bleed and leaves per-line coloring intact, since programs re-open their color on each line. Gated by cj/eat-reset-sgr-at-newline (default on) so it can be disabled if a program ever carries one color across newlines without re-opening it.
|
| |
|
|
| |
Claude Code (and any Ink-style inline TUI) moves the terminal cursor up to redraw its whole block and back to the bottom on every tick; EAT follows the cursor with point, so the Emacs window chases it up and down -- the bounce. Add cj/--eat-tame-scroll on eat-mode-hook: scroll-conservatively 101, scroll-margin 0, and auto-window-vscroll nil, so the window line-scrolls minimally instead of recentering. It doesn't remove the bounce (the inline redraw is the root) but makes each jump gentler.
|
| |
|
|
| |
Add the missing declare-function and defvar declarations that silence the not-known-to-be-defined and free-variable warnings in local-repository, org-webclipper, and weather-config. Rewrite jumper--location-exists-p from dotimes to cl-loop thereis, which fixes a spurious unused-variable warning and short-circuits on the first match. The remaining obsolete-generalized-variable warnings (point in pearl-config, buffer-substring in org-webclipper) come from upstream package macros (pearl, org-web-tools) and are not fixable in our code.
|
| |
|
|
| |
dired's d was dired-flag-file-deletion and D was dired-do-delete, while the ediff diff sat on e. Bind d to the ediff diff and keep D as delete, so the d=diff / D=delete pair is consistent with C-; b and ibuffer. d no longer flags for deletion -- mark with m for batch deletes, then D. Fix the stale commentary (it called d "delete" and D "duplicate") and add which-key labels for the pair.
|
| |
|
|
| |
C-; b d is cj/diff-buffer-with-file and C-; b D is cj/delete-buffer-and-file, but the which-key labels had them reversed -- d read as "delete file" and D as "diff buffer with file". The mislabel made D look like the diff key, so pressing it to see a diff deleted the file instead. Swap the labels to match the actual bindings.
|
| |
|
|
| |
C-/M-left/right were in EAT's default eat-semi-char-non-bound-keys, so they fell through to Emacs and ran left-word/right-word, moving point in the EAT buffer instead of being sent to the program. The terminal's own cursor never moved, so the next keystroke snapped point back to the real cursor -- the "cursor jumps back" symptom when editing claude's input. Bind them to eat-self-input so they forward as word motion, the way ghostel did. Window arrows (S-, C-M-) still reach Emacs for windmove and buffer-move.
|
| |
|
|
| |
EAT's semi-char mode left the bare escape key unbound and treated ESC only as the Meta prefix, so a lone Escape never reached the pty. That is why C-<up>'s tmux copy-mode could not be exited with Escape: tmux's own Escape=cancel binding never saw the key. Bind <escape> to forward ESC to the terminal, so it cancels tmux copy-mode and still works in TUIs like vim. Also bind <escape> in eat-mode-map to return to semi-char, so the same key exits EAT's own emacs and char modes. One exit key for both copy views; q is no longer required.
|
| |
|
|
| |
In the ibuffer buffer list, d now diffs the buffer at point against its saved file (ibuffer-diff-with-file, was on =) and D marks it for deletion (was on d; x still executes the marks).
|
| |
|
|
| |
Remove the dead ghostel app from theme-studio: the GHOSTEL_FACES/SEED data, the registry row, the renderGhostelPreview previewer, and the package_seed test, then regenerate the tool. ansi-color stays since eat inherits it. Rename testutil-ghostel-buffers to testutil-terminal-buffers and drop make-fake-ghostel-buffer; the toggle-filter test now uses the eat fixture, since agents are eat. Fix the comments that still called the agent buffers ghostel (they're eat now) in eat-config and the ai-term and auto-dim test docstrings. I also package-deleted the unused ghostel ELPA package. Full suite green; the remaining ghostel mentions are accurate migration history.
|
| |
|
|
| |
Added Odd Lots, Conversations with Tyler, Plain English with Derek Thompson, and the All-In Podcast. I resolved each channel_id and verified the feed resolves with fresh content before adding; Odd Lots uses Bloomberg's audio playlist since its channel handle is an empty placeholder. Also tagged the two feeds that carried only yt: On with Kara Swisher (on) and Tropical Tidbits (tropical).
|
| | |
|
| |
|
|
| |
mpv resolves streaming-site URLs itself via yt-dlp, so it needs no pre-extracted stream URL or format-guessing the way vlc does. This drives both elfeed's v (cj/play-with-video-player) and the general default.
|
| |
|
|
| |
Opening a video from dirvish routed through cj/xdg-open to the OS default handler, which plays it once. I pulled the video extensions into their own cj/video-extensions list and route them through a new cj/open-video-looping, which launches mpv with --loop-file=inf (the player and its args are both customizable) detached, so the video plays on repeat. Audio and office docs still use the OS default handler. The find-file advice already covers dirvish RET, so this applies wherever a video is opened.
|
| |
|
|
| |
Complete the EAT consolidation by removing ghostel. ai-term and F12 already run on EAT, so ghostel's only remaining users were the dashboard launcher and term-config itself. Migrate the terminal-generic pieces into eat-config: the tmux copy-mode (C-<up> enters it, the same UX and keybinding as before, since agents run EAT over tmux) and the tmux-history capture, swapping ghostel-send-string for a pty write and the mode checks to eat-mode. Repoint the dashboard "Launch Terminal" to the eshell/EAT toggle, swap the face-diagnostic terminal-mode check to eat-mode, and refresh auto-dim's comment. Delete term-config.el and its init require. EAT's default semi-char non-bound-keys already lets windmove, buffer-move, and the Emacs essentials reach the terminal. Tests retargeted; the obsolete ghostel-keymap-exceptions tests are dropped.
|
| |
|
|
| |
Port ai-term from ghostel to EAT. Agents spawn in an EAT terminal running the same tmux session (tmux new-session -A -s aiv-<project>), so the persistence and detach/reattach model is unchanged. A spike confirmed EAT + tmux detach and reattach exactly like ghostel + tmux. The swaps: (ghostel) becomes (eat) with eat-buffer-name carrying the agent name, ghostel-send-string becomes a process-send-string helper, and the M-SPC swap chord is bound directly in eat-semi-char-mode-map (no exception-list plus rebuild dance). Buffer detection was already name-based, so the dispatch, next, and cycle logic is unchanged. Dropped the now-unused suppress-tmux variable. Tests updated to mock eat.
|
| |
|
|
| |
Bring eshell closer to the zsh terminal it replaces. The prompt now shows the git branch (read from .git/HEAD, no subprocess, skipped on remote so TRAMP stays fast) and a [N] exit-status segment when the last command failed, matching the zsh prompt's info. Add a zoxide z command and an eshell-directory-change hook that feeds zoxide add, sharing the same frecency database as the zsh shell. New tests cover the pure prompt helpers.
|
| |
|
|
|
|
| |
xterm-color
Point the F12 dock-and-remember toggle at eshell instead of a standalone EAT zsh shell, so the primary terminal is eshell running through EAT (eat-eshell-mode): elisp functions as commands, TRAMP transparency, and EAT rendering visual commands. Drop the eshell-toggle package and its C-<f12> binding, since F12 covers it now. Drop xterm-color from eshell, since EAT handles ANSI color natively and its TERM=xterm-256color fought EAT's own. The toggle's buffer predicate now matches eshell-mode; the toggle tests and fixture are updated.
|
| |
|
|
| |
Enable eat-eshell-mode so eshell's external commands run in a real EAT terminal: visual commands (vim, htop, less) render properly and ANSI output is faithful, while eshell stays the shell (elisp functions as commands, TRAMP transparency). Activated when eshell loads. EAT handles color natively, so it likely supersedes xterm-color for eshell -- left in place pending an interactive color check.
|