From 5600947e3c07ecc4cba99eb2e97d9f902d41fd33 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 28 Jun 2026 03:39:46 -0400 Subject: docs: condense module commentaries to the terse header contract 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. --- modules/ai-term.el | 124 +++++++++---------------------- modules/calendar-sync.el | 74 ++---------------- modules/calibredb-epub-config.el | 45 ++--------- modules/custom-comments.el | 61 ++------------- modules/dev-fkeys.el | 47 ++---------- modules/flycheck-config.el | 39 ++-------- modules/flyspell-and-abbrev.el | 46 ++---------- modules/font-config.el | 49 ++---------- modules/jumper.el | 69 ++--------------- modules/keyboard-compat.el | 90 +++------------------- modules/mu4e-org-contacts-integration.el | 9 ++- modules/mu4e-org-contacts-setup.el | 6 +- modules/music-config.el | 90 +++------------------- modules/org-agenda-config.el | 49 ++---------- modules/org-webclipper.el | 47 ++---------- modules/test-runner.el | 69 +++-------------- modules/video-audio-recording.el | 105 +++----------------------- 17 files changed, 162 insertions(+), 857 deletions(-) (limited to 'modules') diff --git a/modules/ai-term.el b/modules/ai-term.el index 03c9a4046..4b2495715 100644 --- a/modules/ai-term.el +++ b/modules/ai-term.el @@ -1,4 +1,4 @@ -;;; ai-term.el --- In-Emacs AI-agent launcher with vertical-split terminal -*- lexical-binding: t; -*- +;;; ai-term.el --- AI-agent terminals backed by EAT and tmux -*- lexical-binding: t; -*- ;; Author: Craig Jennings @@ -7,70 +7,18 @@ ;; Layer: 3 (Domain Workflow). ;; Category: D. ;; Load shape: eager. -;; Eager reason: registers four global keys for the AI-agent terminal launcher; a -;; command-loaded deferral candidate. -;; Top-level side effects: four global key bindings. -;; Runtime requires: cl-lib, seq, cj-window-geometry-lib, cj-window-toggle-lib, -;; host-environment. +;; Eager reason: binds M-SPC and the C-; a AI-agent prefix. +;; Top-level side effects: global M-SPC binding and C-; a prefix map. +;; Runtime requires: cl-lib, seq, window-toggle/geometry helpers, host-environment. ;; Direct test load: yes. ;; -;; Picks an AI-agent project (a dir under ~/.emacs.d, ~/code/*, or -;; ~/projects/* containing .ai/protocols.org), opens or reuses a terminal -;; buffer named "agent []", sends the agent's startup -;; instruction to it, and routes the buffer to a side window via -;; display-buffer-alist. When the frame already has a window forming the -;; half the agent would occupy (a right column on a desktop, a bottom row -;; on a laptop), the agent reuses that slot rather than splitting a third -;; window in; toggling off restores the displaced buffer to the slot. -;; Otherwise placement is a host-aware split: a right-side split at 50% -;; width on a desktop, a bottom split at 75% height on a laptop (see -;; `cj/--ai-term-default-direction'). Multiple -;; projects produce multiple coexisting buffers that share the same -;; slot; switching among them is a buffer-switch, not a -;; kill-and-recreate. +;; Opens project-scoped AI agents in EAT buffers backed by tmux sessions. Project +;; candidates come from configured roots that contain .ai/protocols.org. ;; -;; Each project's agent runs inside a tmux session named -;; "" (default prefix "aiv-"). -;; The prefix lets `tmux ls' be filtered to AI-term's own sessions, so -;; after an Emacs crash the project picker can match surviving sessions -;; back to their directories: matched projects sort to the top of the -;; picker (flagged "[detached]" -- session alive, no Emacs buffer -- or -;; "[running]" when a live terminal buffer exists), the rest follow in -;; alphabetical order. -;; -;; Four F-key entry points: -;; -;; - F9 `cj/ai-term' -- DWIM dispatch. If an agent buffer is -;; currently displayed in this frame, F9 toggles it off: when it -;; took over an existing window (a reused slot) the buffer it -;; displaced returns to that slot, when it was split into its own -;; window that window is removed, and when it fills the frame it -;; is buried. Otherwise, if exactly one agent buffer is alive, -;; F9 re-displays it; if zero or two-plus are alive, F9 falls -;; through to the project picker. -;; - C-F9 `cj/ai-term-pick-project' -- always show the project -;; picker, even when an agent buffer is currently displayed. -;; Used when the user wants to start a new project session -;; instead of toggling the current one. -;; - s-F9 `cj/ai-term-next' -- step to the next active agent in the -;; queue. The queue is every active agent in buffer-name order -;; (a stable rotation): attached agents (a live buffer) and -;; detached ones (a live tmux session with no Emacs buffer). -;; Stepping onto a detached agent attaches it. When an agent -;; window is on screen, swap it to the next agent and focus it, -;; wrapping after the last; when none is shown but agents exist, -;; show the first. This is the "switch among existing agents" -;; surface F9 deliberately doesn't provide. -;; - M-F9 `cj/ai-term-close' -- gracefully close an agent: kill its -;; tmux session (stopping the agent process), then its terminal -;; buffer. Its window stays in the layout (swapped to the -;; working buffer), so closing never collapses a split. Confirms -;; first. Targets the current agent, the sole live agent, or -;; prompts among several. -;; -;; Existing windmove (Shift-arrows) handles code <-> agent focus -;; toggling. Buffer-move (C-M-arrows) handles side-swap. Neither -;; needs anything new from this module. +;; Agent display reuses the host-appropriate side slot when possible, otherwise +;; splits right on desktop frames and below on laptop frames. Attached buffers +;; and detached tmux sessions share the same rotation; selecting a detached +;; agent recreates its EAT buffer and attaches to the live session. ;;; Code: @@ -215,7 +163,7 @@ which the step materializes by attaching." Walks `buffer-list' (most-recently-selected first) and returns the first buffer that is not an AI-term agent buffer (per `cj/--ai-term-buffer-p') and is not an internal buffer (name starting -with a space). Used by the single-window F9 toggle-off so dismissing a +with a space). Used by the single-window toggle-off so dismissing a full-frame agent returns to the file the user was working in (e.g. todo.org) rather than swapping in another agent." (seq-find (lambda (b) @@ -287,7 +235,7 @@ looked up in SESSIONS, so the lossy whitespace->hyphen transform in (defun cj/--ai-term-launch-command (dir) "Return the shell command line that runs the AI tool in a project tmux session. -Uses `tmux new-session -A' so a second F9 on the same project reattaches +Uses `tmux new-session -A' so a second toggle on the same project reattaches to the running session instead of spawning a new one. The session name comes from `cj/--ai-term-tmux-session-name'; the first window is named `cj/ai-term-tmux-window-name' (default \"ai\") so a later hand-opened @@ -452,7 +400,7 @@ direction applies. Captured at toggle-off by `cj/--ai-term-display-saved'.") (defvar cj/--ai-term-last-was-bury nil - "Non-nil when the last F9 toggle-off used `bury-buffer'. + "Non-nil when the last toggle-off used `bury-buffer'. Set by `cj/ai-term' in its `toggle-off' branch: t when the agent window was the only window in the frame (so toggle-off buried @@ -462,7 +410,7 @@ buried agent in the current window (the only one) or splitting per the saved direction.") (defvar cj/--ai-term-last-toggle-deleted-split nil - "Non-nil when the last F9 toggle-off deleted the agent's own split window. + "Non-nil when the last toggle-off deleted the agent's own split window. Set t by `cj/--ai-term-toggle-off' only when it actually `delete-window's the agent (a multi-window layout where the agent had its own window); @@ -474,7 +422,7 @@ working window at the edge, displacing its buffer and collapsing the layout -- the toggle must be reversible (off then on returns the same windows).") (defvar cj/--ai-term-last-hidden-buffer nil - "The agent buffer hidden by the most recent F9 toggle-off. + "The agent buffer hidden by the most recent toggle-off. Captured in `cj/ai-term' just before an agent window is torn down, and consumed by `cj/--ai-term-dispatch' so the next toggle-on reopens the @@ -520,7 +468,7 @@ cost of not auto-scaling if the frame itself resizes.") "Capture WINDOW's direction and size into module-level state. Sets `cj/--ai-term-last-direction' and `cj/--ai-term-last-size' -so a subsequent F9 display can restore the user's chosen orientation +so a subsequent display can restore the user's chosen orientation and size. Called at toggle-off (just before the window is torn down). The default direction is host-aware via `cj/--ai-term-default-direction' (used only when WINDOW fills its @@ -544,7 +492,7 @@ action in the chain runs. This is more specific than `display-buffer-use-some-window', which would happily steal any non-selected window (e.g. a code window above the agent split) when the user is focused in agent and -swaps projects via C-F9. The selective lookup here keeps non-agent +swaps projects via C-; a s. The selective lookup here keeps non-agent windows undisturbed and preserves the user's split geometry across project changes." (let ((win (cj/--ai-term-displayed-agent-window))) @@ -598,10 +546,10 @@ When the prior toggle-off was a bury (single-window state, flagged via `cj/--ai-term-last-was-bury') and the frame is still single- window, restore the agent into the selected window in place rather than splitting -- preserves the user's lone-window layout across -F9 toggles. +toggles. Otherwise delegates to `cj/window-toggle-display-saved' against the -F9 state vars, falling back to the host-aware defaults from +toggle state vars, falling back to the host-aware defaults from `cj/--ai-term-default-direction' and `cj/--ai-term-default-size'." (cond ((and cj/--ai-term-last-was-bury (one-window-p)) @@ -627,7 +575,7 @@ through four actions in order: 2. `cj/--ai-term-reuse-existing-agent' -- otherwise, if any window in this frame already shows an agent-prefixed buffer, swap its buffer for the new one (preserves geometry across - project changes via C-F9). + project changes via C-; a s). 3. `cj/--ai-term-reuse-edge-window' -- otherwise, if the frame already has a window forming the half the agent would occupy (the right column on a desktop, the bottom row on a laptop), @@ -773,17 +721,17 @@ Signals `user-error' when no candidates exist." (expand-file-name chosen))))) (defun cj/--ai-term-dispatch () - "Compute the F9 (`cj/ai-term') action without performing it. + "Compute the `cj/ai-term' (C-; a a) action without performing it. Returns one of: - (toggle-off . WINDOW) -- agent is displayed in WINDOW; quit it. - (redisplay-recent . BUFFER) -- 1+ alive agent buffers; show MRU. - (pick-project) -- zero alive agent buffers; prompt. -When 2+ agent buffers are alive, F9 redisplays the most-recently- -selected one rather than opening the project picker. C-F9 is the -explicit \"start a different project\" surface; M-F9 is the explicit -\"switch among existing agents\" surface. F9 keeps a single, simple +When 2+ agent buffers are alive, C-; a a redisplays the most-recently- +selected one rather than opening the project picker. C-; a s is the +explicit \"start a different project\" surface; C-; a n is the explicit +\"switch among existing agents\" surface. C-; a a keeps a single, simple job: toggle whichever agent was last in use. A pure-decision helper so the dispatch logic is exercisable in tests @@ -816,7 +764,7 @@ buffers; reinvoking on the same project reuses its existing terminal. With prefix ARG, display the buffer without selecting its window. -Bound to C-F9 -- always shows the project picker, even when an agent +Bound to C-; a s -- always shows the project picker, even when an agent buffer is currently displayed. EAT renders in terminal frames as well as GUI frames, so this @@ -842,7 +790,7 @@ the agent itself." (other-buffer (window-buffer win) t))))) (defun cj/--ai-term-toggle-off (win) - "Hide the agent shown in WIN for an F9 toggle-off. Always returns nil. + "Hide the agent shown in WIN for a toggle-off. Always returns nil. Two cases, by window count: @@ -855,7 +803,7 @@ Two cases, by window count: force a swap to a non-agent buffer to keep the toggle observable. - Multi-window: collapse the agent split outright by deleting its window, so - the working buffer (e.g. todo.org) reclaims the space. F9 is a pure + the working buffer (e.g. todo.org) reclaims the space. The toggle is a pure show/hide toggle of THE agent split -- it must never surface a different agent. `quit-restore-window' can't guarantee that here: switching among several agents reuses the one slot via `set-window-buffer' (see @@ -897,21 +845,21 @@ Two cases, by window count: nil) (defun cj/ai-term (&optional arg) - "Smart F9 dispatch for the AI-term launcher. + "DWIM dispatch for the AI-term launcher. Bound to C-; a a. Behavior depends on the current state: -- If an AI-term buffer is currently displayed in this frame, F9 +- If an AI-term buffer is currently displayed in this frame, it quits its window (toggle off, buffer stays alive). -- Else, if exactly one alive AI-term buffer exists, F9 re-displays +- Else, if exactly one alive AI-term buffer exists, it re-displays it (DWIM -- the obvious next step is to look at it). -- Else (zero or 2+), F9 falls through to `cj/ai-term-pick-project'. +- Else (zero or 2+), it falls through to `cj/ai-term-pick-project'. With prefix ARG, display the buffer without selecting its window when a buffer is being shown (no effect on the toggle-off branch). -See `cj/ai-term-pick-project' (C-F9) to force the project picker. -M-F9 closes an agent via `cj/ai-term-close'." +See `cj/ai-term-pick-project' (C-; a s) to force the project picker. +C-; a k closes an agent via `cj/ai-term-close'." (interactive "P") (pcase (cj/--ai-term-dispatch) (`(toggle-off . ,win) @@ -945,7 +893,7 @@ Derives the tmux session name from BUFFER's `default-directory' (the project dir the terminal was created in) and kills it so the agent process stops. When BUFFER is shown, swaps its window to a non-agent buffer (the working file) rather than deleting the window -- closing an -agent must not collapse the user's window layout; the F9 hide toggle is +agent must not collapse the user's window layout; the hide toggle is what collapses the split. Then kills BUFFER (suppressing the process-still-running prompt -- the session is already down). No-op when BUFFER isn't an AI-term buffer." @@ -984,7 +932,7 @@ buffers; nil when none are alive." Targets the current agent buffer, the sole live agent, or prompts when several are alive (see `cj/--ai-term-close-target'). Asks for confirmation first -- this kills the running agent process, which can -interrupt work in progress. Bound to M-." +interrupt work in progress. Bound to C-; a k." (interactive) (let ((buffer (cj/--ai-term-close-target))) (unless buffer diff --git a/modules/calendar-sync.el b/modules/calendar-sync.el index c0e0e935a..b684330c8 100644 --- a/modules/calendar-sync.el +++ b/modules/calendar-sync.el @@ -8,75 +8,17 @@ ;; Layer: 3 (Domain Workflow). ;; Category: D/S. ;; Load shape: eager only when calendar-sync.local.el configures calendars. -;; Eager reason: daily-driver workflow; calendars are expected synced at the -;; first session. Timers and network fetches are guarded for batch/test loads. -;; Top-level side effects: defines a calendar keymap and conditionally registers -;; it under cj/custom-keymap; timer and network fetches guarded by -;; config/noninteractive checks. +;; Eager reason: daily agenda workflow; timers and network fetches are guarded. +;; Top-level side effects: defines C-; g map; starts sync only when configured. ;; Runtime requires: cl-lib, subr-x, system-lib, cj-org-text-lib, keybindings. -;; Direct test load: yes (private config optional; degrades cleanly when absent). +;; Direct test load: yes. ;; -;; Simple, reliable one-way sync from multiple calendars to Org mode. -;; Downloads .ics files from calendar URLs (Google, Proton, etc.) and -;; converts to Org format. No OAuth, no API complexity, just file conversion. +;; One-way calendar synchronization from configured .ics/API sources into Org +;; files. Feed URLs may be inline or resolved from auth-source via :secret-host. ;; -;; Features: -;; - Multi-calendar support (sync multiple calendars to separate files) -;; - Pure Emacs Lisp .ics parser (no external dependencies) -;; - Recurring event support (RRULE expansion) -;; - Timer-based automatic sync (every 60 minutes, configurable) -;; - Self-contained in .emacs.d (no cron, portable across machines) -;; - Read-only (can't corrupt source calendars) -;; - Works with Chime for event notifications -;; -;; Recurring Events (RRULE): -;; -;; Calendar recurring events are defined once with an RRULE -;; (recurrence rule) rather than as individual event instances. This -;; module expands recurring events into individual org entries. -;; -;; Expansion uses a rolling window approach: -;; - Past: 3 months before today -;; - Future: 12 months after today -;; -;; Every sync regenerates the entire file based on the current date, -;; so the window automatically advances as time passes. Old events -;; naturally fall off after 3 months, and new future events appear -;; as you approach them. -;; -;; Supported RRULE patterns: -;; - FREQ=DAILY: Daily events -;; - FREQ=WEEKLY;BYDAY=MO,WE,FR: Weekly on specific days -;; - FREQ=MONTHLY: Monthly events (same day each month) -;; - FREQ=YEARLY: Yearly events (anniversaries, birthdays) -;; - INTERVAL: Repeat every N periods (e.g., every 2 weeks) -;; - UNTIL: End date for recurrence -;; - COUNT: Maximum occurrences (combined with date range limit) -;; -;; Setup: -;; 1. Configure calendars in your init.el: -;; (setq calendar-sync-calendars -;; '((:name "google" -;; :url "https://calendar.google.com/calendar/ical/.../basic.ics" -;; :file gcal-file) -;; (:name "proton" -;; :url "https://calendar.proton.me/api/calendar/v1/url/.../calendar.ics" -;; :file pcal-file))) -;; -;; 2. Load and start: -;; (require 'calendar-sync) -;; (calendar-sync-start) -;; -;; 3. Add to org-agenda (optional): -;; (dolist (cal calendar-sync-calendars) -;; (add-to-list 'org-agenda-files (plist-get cal :file))) -;; -;; Usage: -;; - M-x calendar-sync-now ; Sync all or select specific calendar -;; - M-x calendar-sync-start ; Start auto-sync -;; - M-x calendar-sync-stop ; Stop auto-sync -;; - M-x calendar-sync-toggle ; Toggle auto-sync -;; - M-x calendar-sync-status ; Show sync status for all calendars +;; The parser expands recurring events into a rolling window around today, +;; regenerates target Org files on each sync, and keeps source calendars +;; read-only. Commands under C-; g start, stop, toggle, inspect, and run syncs. ;;; Code: diff --git a/modules/calibredb-epub-config.el b/modules/calibredb-epub-config.el index f833c2503..cd8101db1 100644 --- a/modules/calibredb-epub-config.el +++ b/modules/calibredb-epub-config.el @@ -6,46 +6,17 @@ ;; Layer: 4 (Optional). ;; Category: O/D/P. ;; Load shape: eager. -;; Eager reason: none; optional ebook workflow, a command-loaded deferral -;; candidate for Phase 4. -;; Top-level side effects: one add-hook, one advice-add, package config. -;; Runtime requires: user-constants, subr-x. +;; Eager reason: none; ebook commands can load by command. +;; Top-level side effects: one hook, one advice, package config. +;; Runtime requires: user-constants, subr-x, transient. ;; Direct test load: yes. ;; -;; This module provides a comprehensive ebook management and reading experience -;; within Emacs, integrating CalibreDB for library management and Nov for EPUB -;; reading. +;; CalibreDB and Nov integration for browsing the Calibre library and reading +;; EPUBs inside Emacs. The module adds a curated CalibreDB transient, filter +;; helpers, Nov typography, image centering, and reader-to-library navigation. ;; -;; FEATURES: -;; - CalibreDB integration for managing your Calibre ebook library -;; - Nov mode for reading EPUB files with customized typography and layout -;; - Seamless navigation between Nov reading buffers and CalibreDB entries -;; - Image centering in EPUB documents without modifying buffer text -;; - Quick filtering and searching within your ebook library -;; -;; KEY BINDINGS: -;; - M-B: Open CalibreDB library browser -;; - In CalibreDB search mode: -;; - l: Filter by tag -;; - L: Clear all filters -;; - In Nov mode: -;; - z: Open current EPUB in external viewer (zathura) -;; - C-c C-b: Jump to CalibreDB entry for current book -;; - m: Set bookmark -;; - b: List bookmarks -;; -;; WORKFLOW: -;; 1. Press M-B to browse your Calibre library -;; 2. Use filters (l for tags, L to clear) to narrow results -;; 3. Open an EPUB to read it in Nov with optimized typography -;; 4. While reading, use C-c C-b to jump back to the book's metadata -;; 5. Use z to open in external reader when needed -;; -;; CONFIGURATION NOTES: -;; - Prefers EPUB format when available, falls back to PDF -;; - Centers images in EPUB documents using display properties -;; - Applies custom typography with larger fonts for comfortable reading -;; - Uses visual-fill-column for centered text with appropriate margins +;; EPUB is preferred when available; external opening remains available for +;; formats or workflows better handled outside Emacs. ;;; Code: diff --git a/modules/custom-comments.el b/modules/custom-comments.el index 231a03860..a2604a558 100644 --- a/modules/custom-comments.el +++ b/modules/custom-comments.el @@ -5,62 +5,17 @@ ;; Layer: 2 (Core UX). ;; Category: L/C. ;; Load shape: eager. -;; Eager reason: registers its C-; C comment submap at load. Currently eager by -;; init order; a deferral candidate for Phase 3/4 (command/autoload + -;; registration API). -;; Top-level side effects: defines cj/comment-map, registers it under C-; C. +;; Eager reason: registers C-; C comment helpers. +;; Top-level side effects: defines and registers cj/comment-map. ;; Runtime requires: keybindings. -;; Direct test load: yes (requires keybindings explicitly). +;; Direct test load: yes. ;; -;; This module provides custom comment formatting and manipulation utilities for code editing. -;; -;; Functions include: -;; - deleting all comments in a buffer, -;; - reformatting commented text into single-line paragraphs, -;; - creating centered comment headers with customizable separator characters, -;; - creating comment boxes around text -;; - inserting hyphen-style centered comments. -;; -;; These utilities help create consistent, well-formatted code comments and section headers. -;; Bound to keymap prefix: C-; C -;; -;; Comment Style Patterns: -;; -;; inline-border: -;; ========== inline-border ========== -;; -;; simple-divider: -;; ==================================== -;; simple-divider -;; ==================================== -;; -;; padded-divider: -;; ==================================== -;; padded-divider -;; ==================================== -;; -;; box: -;; ************************************ -;; * box * -;; ************************************ -;; -;; heavy-box: -;; ************************************ -;; * * -;; * heavy-box * -;; * * -;; ************************************ -;; -;; unicode-box: -;; ┌──────────────────────────────────┐ -;; │ unicode-box │ -;; └──────────────────────────────────┘ -;; -;; block-banner: -;; /************************************ -;; * block-banner -;; ************************************/ +;; Comment editing helpers: delete comments, reflow commented regions, and insert +;; consistent section headers or boxes using the current mode's comment syntax. ;; +;; Public commands live under C-; C. Decoration helpers validate single printable +;; characters before generating comment borders. + ;;; Code: (require 'keybindings) ;; provides cj/custom-keymap diff --git a/modules/dev-fkeys.el b/modules/dev-fkeys.el index 9fdfa5b3f..80b43600b 100644 --- a/modules/dev-fkeys.el +++ b/modules/dev-fkeys.el @@ -5,48 +5,17 @@ ;; Layer: 2 (Core UX). ;; Category: C. ;; Load shape: eager. -;; Eager reason: the F4/F6 developer command entry points. -;; Top-level side effects: six global F-key bindings; conditionally registers a -;; C-; P binding. +;; Eager reason: binds the F4/F6 developer command entry points. +;; Top-level side effects: global F-key bindings and optional C-; P binding. ;; Runtime requires: cl-lib, system-lib, keybindings. -;; Direct test load: yes (requires keybindings explicitly). +;; Direct test load: yes. ;; -;; Project-aware F-key block for developer workflows: +;; Project-aware F-key dispatchers. F4 chooses compile/run/clean commands by +;; project markers; C-F4 and M-F4 are fast paths. F6 runs all project tests or +;; the current file's tests using language-specific command builders. ;; -;; F4 completing-read of compile/run candidates filtered by project type -;; C-F4 fast path: compile only (no-op on interpreted projects) -;; M-F4 fast path: clean + rebuild (no-op on interpreted projects) -;; S-F4 recompile (built-in) -;; F6 completing-read of test candidates: All tests / Current file's tests -;; C-F6 fast path: current file's tests -;; -;; F4 project-type detection runs against the projectile root and falls back -;; to \\='unknown when no marker matches. Interpreted markers are checked -;; before compiled markers, so a Python or Node project that also has a -;; Makefile for tasks classifies as interpreted. -;; -;; F6 \"All tests\" delegates to `projectile-test-project'. F6 \"Current -;; file's tests\" detects the language by extension, derives the runner -;; command (elisp via the project Makefile, Python via pytest, Go via the -;; package), and pipes through `compile' from the projectile root. -;; TypeScript / JavaScript are detected but punted for v1 — the function -;; signals a user-error rather than guessing a runner. -;; -;; M-F6 is reserved for Phase 2b (\"Run a test...\" menu entry with -;; per-language test-name discovery). Phase 2b also adds buffer-local -;; last-test memory and tree-sitter-based discovery for Python / Go / -;; TypeScript. The tree-sitter discovery uses a capture-then-filter pattern -;; (queries without `:match' / `:equal' / `:pred' predicates, with the -;; pattern filter applied in Elisp) to sidestep Emacs bug #79687 — Emacs -;; 30.2 emits unsuffixed `#match' predicates that libtree-sitter 0.26 -;; rejects. The fix lives on Emacs master (commit b0143530) and is -;; targeted at Emacs 31; it has not been backported to the emacs-30 -;; branch as of 2026-05-03. See Mike Olson's writeup at -;; https://mwolson.org/blog/emacs/2026-04-20-fixing-typescript-ts-mode-in-emacs-30-2/ -;; for the same workaround applied to font-lock. -;; -;; F7 (coverage) is wired in coverage-core.el. F5 is reserved for the debug -;; ticket and intentionally left unbound here. +;; Interpreted markers win over compiled markers so task Makefiles do not turn +;; Python/Node projects into compile-first projects. ;;; Code: diff --git a/modules/flycheck-config.el b/modules/flycheck-config.el index 1afd3ae6c..613817444 100644 --- a/modules/flycheck-config.el +++ b/modules/flycheck-config.el @@ -6,40 +6,17 @@ ;; Layer: 2 (Core UX). ;; Category: C/P. ;; Load shape: eager. -;; Eager reason: general linting setup; spec target is hook-loaded, a deferral -;; candidate. -;; Top-level side effects: package configuration via use-package, binds into -;; cj/custom-keymap through use-package :map. +;; Eager reason: linting keymap and mode hooks; could become hook-loaded. +;; Top-level side effects: package config and C-; ? binding. ;; Runtime requires: keybindings. -;; Direct test load: yes (requires keybindings explicitly). +;; Direct test load: yes. ;; -;; This file configures Flycheck for on-demand syntax and grammar checking. -;; - Flycheck starts automatically only in sh-mode and emacs-lisp-mode - -;; - This binds a custom helper (=cj/flycheck-list-errors=) to "C-; ?" -;; for popping up Flycheck's error list in another window. - -;; - It also customizes Checkdoc to suppress only the "sentence-end-double-space" -;; and "warn-escape" warnings. - -;; - It registers LanguageTool for comprehensive grammar checking of prose files -;; (text-mode, markdown-mode, gfm-mode, org-mode). - -;; Note: Grammar checking is on-demand only to avoid performance issues. -;; Hitting "C-; ?" runs cj/flycheck-prose-on-demand if in an org buffer. - -;; The cj/flycheck-prose-on-demand function: -;; - Turns on flycheck for the local buffer -;; - Enables LanguageTool checker -;; - Triggers an immediate check -;; - Displays errors in the *Flycheck errors* buffer - -;; Installation: -;; On Arch Linux: -;; sudo pacman -S languagetool +;; Flycheck configuration for automatic shell/Elisp linting and on-demand prose +;; grammar checks. C-; ? opens the Flycheck error list, enabling prose checking +;; first when appropriate. ;; -;; The wrapper script at scripts/languagetool-flycheck formats LanguageTool's -;; JSON output into flycheck-compatible format. It requires Python 3. +;; LanguageTool uses scripts/languagetool-flycheck to adapt JSON output to +;; Flycheck's checker protocol. ;;; Code: diff --git a/modules/flyspell-and-abbrev.el b/modules/flyspell-and-abbrev.el index 376a9dc51..b73bfdf32 100644 --- a/modules/flyspell-and-abbrev.el +++ b/modules/flyspell-and-abbrev.el @@ -6,48 +6,18 @@ ;; Layer: 2 (Core UX). ;; Category: C/P. ;; Load shape: eager. -;; Eager reason: text-mode spelling and abbrev hooks; spec target is hook-loaded. -;; Top-level side effects: package configuration via use-package (mode hooks). +;; Eager reason: text-mode spelling and abbrev hooks. +;; Top-level side effects: package configuration via use-package. ;; Runtime requires: cl-lib. ;; Direct test load: yes. ;; -;; WORKFLOW: -;; This module provides intelligent spell checking with automatic abbreviation -;; creation to prevent repeated misspellings. +;; On-demand Flyspell workflow with automatic abbrev creation from accepted +;; corrections. C-' checks/corrects nearby misspellings; C-c f toggles Flyspell +;; with mode-aware behavior. ;; -;; KEYBINDINGS: -;; C-' - Main spell check interface (cj/flyspell-then-abbrev) -;; C-c f - Toggle flyspell on/off (cj/flyspell-toggle) -;; M-o - Access 'other options' during correction (save to dictionary, etc.) -;; -;; SPELL CHECKING WORKFLOW: -;; 1. Press C-' to start spell checking -;; 2. Finds the nearest misspelled word above the cursor -;; 3. Prompts for correction or allows saving to personal dictionary -;; 4. Press C-' again to move to the next misspelling -;; 5. Each correction automatically creates an abbrev for future auto-expansion -;; -;; FLYSPELL ACTIVATION: -;; Flyspell is NOT automatically enabled. You activate it manually: -;; - C-c f - Toggle flyspell on (uses smart mode detection) or off -;; - C-' - Runs flyspell-buffer then starts correction workflow -;; -;; When enabled, flyspell adapts to the buffer type: -;; - Programming modes (prog-mode): Only checks comments and strings -;; - Text modes (text-mode): Checks all text -;; - Other modes: Must enable manually with C-c f -;; -;; ABBREVIATION AUTO-EXPANSION: -;; Each spell correction creates an abbrev that auto-expands the misspelling -;; to the correct spelling when you type it in the future. This significantly -;; increases typing speed over time. -;; -;; Original idea from Artur Malabarba: -;; http://endlessparentheses.com/ispell-and-abbrev-the-perfect-auto-correct.html -;; -;; NOTES: -;; The default flyspell keybinding "C-;" is unbound in this config as it's -;; used for the custom keymap (cj/custom-keymap). +;; Flyspell is not enabled globally. Programming buffers check comments/strings +;; when enabled; prose buffers check all text. The default C-; Flyspell binding +;; is intentionally left free for cj/custom-keymap. ;;; Code: diff --git a/modules/font-config.el b/modules/font-config.el index 3272a946e..cb060b7be 100644 --- a/modules/font-config.el +++ b/modules/font-config.el @@ -6,51 +6,18 @@ ;; Layer: 2 (Core UX). ;; Category: C/P/S. ;; Load shape: eager. -;; Eager reason: font setup for the first frame, plus font keybindings. -;; Top-level side effects: binds five global font keys, runs font-installation -;; checks, configures packages via use-package. +;; Eager reason: first-frame font setup and font keybindings. +;; Top-level side effects: font keys, font checks, package config. ;; Runtime requires: host-environment, keybindings. ;; Direct test load: yes. ;; -;; This module provides font configuration, including: -;; -;; 1. Font Management: -;; - Dynamic font preset switching via `fontaine' package -;; - Separate configurations for fixed-pitch and variable-pitch fonts -;; - Multiple size presets for different viewing contexts -;; - Per-frame font configuration tracking for daemon mode compatibility -;; -;; 2. Icon Support: -;; - All-the-icons integration with automatic font installation -;; - Nerd fonts support for enhanced icons in terminals and GUI -;; - Platform-specific emoji font configuration (Noto, Apple, Segoe) -;; - Emojify package for emoji rendering and insertion -;; -;; 3. Typography Enhancements: -;; - Programming ligatures via `ligature' package -;; - Mode-specific ligature rules for markdown and programming -;; - Text scaling keybindings for quick size adjustments -;; -;; 4. Utility Functions: -;; - `cj/font-installed-p': Check font availability -;; - `cj/display-available-fonts': Interactive font browser with samples -;; - Frame-aware font application for client/server setups -;; -;; Configuration Notes: -;; - Default preset: BerkeleyMono Nerd Font; height 120 on laptops, 140 on desktops -;; - Variable pitch: Lexend in the default preset; Merriweather for fallback presets -;; - Handles both standalone and daemon mode Emacs instances -;; - Emoji fonts selected based on OS availability -;; -;; Keybindings: -;; - M-S-f: Select font preset (fontaine-set-preset) -;; - C-z F: Display available fonts -;; - C-+/C-=: Increase text scale -;; - C--/C-_: Decrease text scale -;; - C-c E i: Insert emoji -;; - C-c E l: List emojis -;; +;; Configures fontaine presets, text scaling keys, icon/emoji fonts, and +;; programming ligatures. Presets are applied per frame so daemon clients get +;; the intended fixed/variable pitch sizes. ;; +;; Also carries font-rendering safeguards for known HarfBuzz/font-cache crashes +;; triggered by emoji and Arabic shaping in this setup. + ;;; Code: (require 'host-environment) diff --git a/modules/jumper.el b/modules/jumper.el index 61b6464a5..1fbd1293b 100644 --- a/modules/jumper.el +++ b/modules/jumper.el @@ -11,72 +11,17 @@ ;; Layer: 4 (Optional). ;; Category: O/L. ;; Load shape: eager. -;; Eager reason: none; navigation helper, a command-loaded deferral candidate. -;; Top-level side effects: defines a jumper keymap. +;; Eager reason: none; jump commands can autoload. +;; Top-level side effects: defines jumper keymap. ;; Runtime requires: cl-lib. ;; Direct test load: yes. ;; -;; Jumper provides a simple way to store and jump between locations -;; in your codebase without needing to remember register assignments. +;; Small register-backed jump list. Locations are stored in numbered registers, +;; shown through completion with file/line context, and removed explicitly when +;; no longer useful. ;; -;; PURPOSE: -;; -;; When working on large codebases, you often need to jump between -;; multiple related locations: a function definition, its tests, its -;; callers, configuration files, etc. Emacs registers are perfect for -;; this, but require you to remember which register you assigned to -;; which location. Jumper automates register management, letting you -;; focus on your work instead of bookkeeping. -;; -;; WORKFLOW: -;; -;; 1. Navigate to an important location in your code -;; 2. Press M-SPC SPC to store it (automatically assigned to register 0) -;; 3. Continue working, storing more locations as needed (registers 1-9) -;; 4. Press M-SPC j to jump back to any stored location -;; 5. Select from the list using completion (shows file, line, context) -;; 6. Press M-SPC d to remove locations you no longer need -;; -;; RECOMMENDED USAGE: -;; -;; Store locations temporarily while working on a feature: -;; - Store the main function you're implementing -;; - Store the test file where you're writing tests -;; - Store the caller that needs updating -;; - Store the documentation that needs changes -;; - Jump between them freely as you work -;; - Clear them when done with the feature -;; -;; SPECIAL BEHAVIORS: -;; -;; - Duplicate prevention: Storing the same location twice shows a message -;; instead of wasting a register slot. -;; -;; - Single location toggle: When only one location is stored, M-SPC j -;; toggles between that location and your current position. Perfect for -;; rapid back-and-forth between two related files. -;; -;; - Last location tracking: The last position before each jump is saved -;; in register 'z', allowing quick "undo" of navigation. -;; -;; - Smart selection: With multiple locations, completing-read shows -;; helpful context: "[0] filename.el:42 - function definition..." -;; -;; KEYBINDINGS: -;; -;; M-SPC SPC Store current location in next available register -;; M-SPC j Jump to a stored location (with completion) -;; M-SPC d Delete a stored location from the list -;; -;; CONFIGURATION: -;; -;; You can customize the prefix key and maximum locations: -;; -;; (setq jumper-prefix-key "C-c j") ; Change prefix key -;; (setq jumper-max-locations 20) ; Store up to 20 locations -;; -;; Note: Changing jumper-max-locations requires restarting Emacs or -;; manually reinitializing jumper--registers. +;; A single stored location toggles with the current point; each jump records the +;; previous point in register z for a quick return path. ;;; Code: diff --git a/modules/keyboard-compat.el b/modules/keyboard-compat.el index 914a343a6..172f96c7b 100644 --- a/modules/keyboard-compat.el +++ b/modules/keyboard-compat.el @@ -6,90 +6,18 @@ ;; Layer: 1 (Foundation). ;; Category: F/S. ;; Load shape: eager. -;; Eager reason: normalizes terminal/GUI key input so the first session's -;; keybindings resolve consistently. -;; Top-level side effects: adds `cj/keyboard-compat-terminal-setup' to -;; `emacs-startup-hook'. +;; Eager reason: normalizes terminal/GUI key input before custom bindings matter. +;; Top-level side effects: adds cj/keyboard-compat-terminal-setup to startup. ;; Runtime requires: host-environment. -;; Direct test load: yes (registers a startup hook; batch-safe). +;; Direct test load: yes. ;; -;; This module fixes keyboard input differences between terminal and GUI Emacs. +;; Normalizes Meta+Shift bindings across GUI and terminal frames. GUI frames +;; translate M-uppercase events to explicit M-S-lowercase keys; terminal frames +;; decode arrow escape sequences before key lookup so ESC O prefixes do not trip +;; M-S bindings. ;; -;; THE PROBLEM: Meta+Shift keybindings behave differently in terminal vs GUI -;; ========================================================================= -;; -;; In Emacs, there are two ways to express "Meta + Shift + o": -;; -;; 1. M-O (Meta + uppercase O) - key code 134217807 -;; 2. M-S-o (Meta + explicit Shift modifier + lowercase o) - key code 167772271 -;; -;; These are NOT the same key in Emacs! -;; -;; GUI Emacs behavior: -;; When you press Meta+Shift+o on your keyboard, GUI Emacs receives M-O -;; (uppercase O). It does NOT receive M-S-o. This is because the keyboard -;; sends Shift+o as uppercase 'O', not as a Shift modifier plus lowercase 'o'. -;; -;; Terminal Emacs behavior: -;; Terminals send escape sequences for special keys. Arrow keys send: -;; - Up: ESC O A -;; - Down: ESC O B -;; - Right: ESC O C -;; - Left: ESC O D -;; -;; The problem: ESC O is interpreted as M-O by Emacs! So if you bind M-O -;; to a function, pressing the up arrow sends "ESC O A", Emacs sees "M-O" -;; and triggers your function instead of moving up. Arrow keys break. -;; -;; THE SOLUTION: Different handling for each display type -;; ====================================================== -;; -;; For terminal mode (handled by cj/keyboard-compat-terminal-setup): -;; - Use input-decode-map to translate arrow escape sequences BEFORE -;; any keybinding lookup. ESC O A becomes [up], not M-O followed by A. -;; - Keybindings use M-S-o syntax (some terminals support explicit Shift) -;; - Disable graphical icons that show as unicode artifacts -;; -;; For GUI mode (handled by cj/keyboard-compat-gui-setup): -;; - Use key-translation-map to translate M-O to M-S-o BEFORE lookup -;; - This way, pressing Meta+Shift+o (which sends M-O) gets translated -;; to M-S-o, matching the keybinding definitions -;; - All 18 Meta+Shift keybindings work correctly -;; -;; WHY NOT JUST USE M-O FOR KEYBINDINGS? -;; ===================================== -;; -;; We could bind to M-O directly, but: -;; 1. Terminal arrow keys would break (ESC O prefix conflict) -;; 2. We'd need to maintain two sets of bindings (M-O for GUI, something -;; else for terminal) -;; -;; By using M-S-o syntax everywhere and translating M-O -> M-S-o in GUI mode, -;; we have one consistent set of keybindings that work everywhere. -;; -;; KEYBINDINGS AFFECTED: -;; ==================== -;; -;; The following M-S- keybindings are translated from M-uppercase in GUI: -;; -;; M-O -> M-S-o cj/kill-other-window (undead-buffers.el) -;; M-M -> M-S-m cj/kill-all-other-buffers-and-windows (undead-buffers.el) -;; M-Y -> M-S-y yank-media (keybindings.el) -;; M-F -> M-S-f fontaine-set-preset (font-config.el) -;; M-W -> M-S-w wttrin (weather-config.el) -;; M-E -> M-S-e eww (eww-config.el) -;; M-L -> M-S-l cj/switch-themes (ui-theme.el) -;; M-R -> M-S-r cj/elfeed-open (elfeed-config.el) -;; M-V -> M-S-v cj/split-and-follow-right (ui-navigation.el) -;; M-H -> M-S-h cj/split-and-follow-below (ui-navigation.el) -;; M-T -> M-S-t toggle-window-split (ui-navigation.el) -;; M-Z -> M-S-z cj/undo-kill-buffer (ui-navigation.el) -;; M-U -> M-S-u winner-undo (ui-navigation.el) -;; M-D -> M-S-d dwim-shell-commands-menu (dwim-shell-config.el) -;; M-I -> M-S-i edit-indirect-region (text-config.el) -;; M-C -> M-S-c time-zones (chrono-tools.el) -;; M-B -> M-S-b calibredb (calibredb-epub-config.el) -;; M-K -> M-S-k show-kill-ring (show-kill-ring.el) +;; Also provides terminal-specific display fallbacks, such as hiding icon glyphs +;; that render poorly outside GUI frames. ;;; Code: diff --git a/modules/mu4e-org-contacts-integration.el b/modules/mu4e-org-contacts-integration.el index daa12701a..6062b8cf5 100644 --- a/modules/mu4e-org-contacts-integration.el +++ b/modules/mu4e-org-contacts-integration.el @@ -2,8 +2,13 @@ ;; author: Craig Jennings ;;; Commentary: -;; This module provides seamless integration between org-contacts and mu4e's -;; email composition, enabling automatic contact completion in email fields. +;; +;; Completion-at-point integration between org-contacts and mu4e/org-msg compose +;; buffers. Header fields complete against org contact email strings; message +;; bodies keep their normal TAB behavior. +;; +;; Dependencies are optional at file load. Activation is a no-op when mu4e or +;; org-contacts is unavailable so the wider config can still load. ;;; Code: diff --git a/modules/mu4e-org-contacts-setup.el b/modules/mu4e-org-contacts-setup.el index 64e9a611f..bfb9b1f24 100644 --- a/modules/mu4e-org-contacts-setup.el +++ b/modules/mu4e-org-contacts-setup.el @@ -2,8 +2,10 @@ ;; author: Craig Jennings ;;; Commentary: -;; Simple setup file to enable org-contacts integration with mu4e. -;; Add this to your mail-config.el or load it after both mu4e and org-contacts. +;; +;; Thin activation wrapper for mu4e-org-contacts-integration. If mu4e is loaded, +;; enable org-contacts completion and disable mu4e's internal contact collector +;; so completion has one source of truth. ;;; Code: diff --git a/modules/music-config.el b/modules/music-config.el index c62f0c614..86f6eb130 100644 --- a/modules/music-config.el +++ b/modules/music-config.el @@ -5,90 +5,18 @@ ;; Layer: 4 (Optional). ;; Category: O/D/P/S. ;; Load shape: eager. -;; Eager reason: none; optional music workflow that registers a music keymap, a -;; command-loaded deferral candidate. EMMS hooks should run only after EMMS. -;; Top-level side effects: defines a music keymap under cj/custom-keymap, one -;; global key, package config. +;; Eager reason: none; optional music workflow that registers a music keymap. +;; Top-level side effects: defines C-; m map, one global key, package config. ;; Runtime requires: subr-x, user-constants, keybindings. -;; Direct test load: yes (requires keybindings explicitly). +;; Direct test load: yes. ;; -;; Music management in Emacs via EMMS with MPV backend. -;; Focus: simple, modular helpers; consistent error handling; streamlined UX. -;; -;; Highlights: -;; - Fuzzy add: select files/dirs; dirs have trailing /; case-insensitive; stable order -;; - Recursive directory add -;; - Dired/Dirvish integration (add selection) -;; - M3U playlist save/load/edit/reload -;; - Radio station M3U creation (streaming URLs supported) -;; - Playlist window toggling -;; - Consume mode (remove tracks after playback) -;; - MPV as player (no daemon required) -;; -;; Keybindings (playlist-mode-map): -;; -;; Aligned with ncmpcpp defaults where possible (83% match). -;; Additional EMMS-specific bindings for features ncmpcpp lacks. -;; -;; Key Action ncmpcpp default Match -;; ─── ────── ─────────────── ───── -;; Playback -;; SPC pause add_item * -;; s stop stop ✓ -;; > / n next track next ✓ -;; < / P previous track previous ✓ -;; p play selected (enter) ✓ -;; f seek forward seek_forward ✓ -;; b seek backward seek_backward ✓ -;; -;; Toggles -;; r repeat playlist toggle_repeat ✓ -;; t repeat track (none) + -;; z random toggle_random ✓ -;; x consume toggle_crossfade * -;; Z shuffle shuffle ✓ -;; -;; Volume -;; + / = volume up volume_up ✓ -;; - volume down volume_down ✓ -;; -;; Info -;; i song info show_song_info ✓ -;; o jump to playing jump_to_playing ✓ -;; -;; Playlist management -;; a add music (fuzzy) add_selected ✓ -;; c / C clear playlist clear_playlist ✓ -;; S save playlist (none) + -;; L load playlist (none) + -;; E edit playlist M3U (none) + -;; g reload playlist (none) + -;; A append track to M3U (none) + -;; q quit/bury quit ✓ -;; -;; Track reordering -;; S-up move track up (shift-up) ✓ -;; S-down move track down (shift-down) ✓ -;; C-up move track up (alias) (none) + -;; C-down move track down (alias) (none) + -;; -;; Other -;; R create radio station (none) + -;; -;; Legend: ✓ = matches ncmpcpp default -;; * = intentional divergence (see below) -;; + = EMMS-only feature -;; -;; Intentional divergences from ncmpcpp defaults: -;; -;; SPC/p swap: ncmpcpp defaults p=pause, SPC=add_item_to_playlist. -;; This config uses SPC=pause (more natural in Emacs) and p=play -;; selected track. Pause via SPC is a common media player convention. -;; -;; x=consume vs crossfade: ncmpcpp's crossfade is an mpd daemon -;; feature. EMMS uses mpv directly, so consume mode (remove tracks -;; after playback) is more useful here. +;; EMMS setup using an mpv subprocess player, M3U playlist helpers, fuzzy +;; file/directory adds, Dired/Dirvish integration, radio-station creation, and +;; playlist window toggling. ;; +;; The playlist keymap intentionally follows ncmpcpp where it maps cleanly, with +;; EMMS-specific additions for M3U editing and consume mode. + ;;; Code: (require 'subr-x) diff --git a/modules/org-agenda-config.el b/modules/org-agenda-config.el index 3234cc929..9ccd21d7b 100644 --- a/modules/org-agenda-config.el +++ b/modules/org-agenda-config.el @@ -6,51 +6,18 @@ ;; Layer: 3 (Domain Workflow). ;; Category: D/S. ;; Load shape: eager. -;; Eager reason: daily agenda workflow; the user expects agenda available at the -;; first session. -;; Top-level side effects: one add-hook and an idle timer that builds the agenda -;; file cache 10s after startup (guarded; spec tracks the cache lifecycle). +;; Eager reason: agenda should be available in the first session. +;; Top-level side effects: agenda hooks plus guarded idle cache build. ;; Runtime requires: user-constants, system-lib, cj-cache-lib. ;; Direct test load: yes. ;; -;; Performance: -;; - Caches agenda file list to avoid scanning projects directory on every view -;; - Cache builds asynchronously 10 seconds after Emacs startup (non-blocking) -;; - First agenda view uses cache if ready, otherwise builds synchronously -;; - Subsequent views are instant (cached) -;; - Cache auto-refreshes after 1 hour -;; - Manual refresh: M-x cj/org-agenda-refresh-files (e.g., after adding projects) +;; Org agenda configuration for global, project-scoped, and buffer-scoped task +;; views. F8 opens the main agenda; modified F8 bindings narrow by project, +;; current buffer, or task list. ;; -;; Agenda views are tied to the F8 (fate) key. -;; -;; "We are what we repeatedly do. -;; Excellence, then, is not an act, but a habit" -;; -- Aristotle -;; -;; "...watch your actions, they become habits; -;; watch your habits, they become character; -;; watch your character, for it becomes your destiny." -;; -- Lao Tzu -;; -;; -;; f8 - MAIN AGENDA which organizes all tasks and events into: -;; - all unfinished priority A tasks -;; - the weekly schedule, including the habit consistency graph -;; - all priority B tasks -;; -;; C-f8 - PROJECT AGENDA showing the main agenda filtered to a single project. -;; Prompts for project selection, then shows overdue/hi-pri/schedule/B tasks -;; scoped to that project's todo.org plus all calendars and inbox. -;; -;; s-f8 - TASK LIST containing all tasks from all agenda targets. -;; -;; M-f8 - TASK LIST containing all tasks from just the current org-mode buffer. -;; -;; NOTE: -;; Files that contain information relevant to the agenda are: the inbox, the -;; schedule-file, the synced calendars, and the per-project todo.org files found -;; in immediate subdirectories of projects-dir. (org-roam notes are refile -;; targets, not agenda sources -- see org-refile-config.el.) +;; Agenda files come from inbox, schedule files, synced calendars, and immediate +;; project todo.org files. The file list is cached and rebuilt asynchronously to +;; keep normal agenda opens fast. ;;; Code: (require 'user-constants) diff --git a/modules/org-webclipper.el b/modules/org-webclipper.el index f32cad3fd..a51350f51 100644 --- a/modules/org-webclipper.el +++ b/modules/org-webclipper.el @@ -5,50 +5,17 @@ ;; Layer: 4 (Optional). ;; Category: O/D/P. ;; Load shape: eager. -;; Eager reason: none; web clipping runs via org-protocol/command, a Phase 4 -;; protocol/command-loaded deferral candidate. +;; Eager reason: none; protocol and direct clipping can load on command. ;; Top-level side effects: org-protocol handler registration via use-package. -;; Runtime requires: none (configures packages via use-package). +;; Runtime requires: none. ;; Direct test load: yes. ;; -;; This package provides a seamless "fire-and-forget" workflow for clipping -;; web pages from the browser directly into an Org file using org-protocol -;; and org-web-tools. +;; Captures web pages into Org from org-protocol, EWW, or W3M. The protocol path +;; records URL/title dynamically around org-capture; the direct path clips the +;; current browser buffer. ;; -;; Features: -;; - Browser bookmarklet integration via org-protocol -;; - Automatic conversion to Org format using eww-readable and Pandoc -;; - One-click capture from any web page -;; - Preserves page structure and formatting -;; - Smart heading adjustment (removes page title, demotes remaining headings) -;; -;; Setup: -;; 1. Ensure this file is loaded in your Emacs configuration -;; 2. Make sure emacsclient is configured for org-protocol -;; 3. Add the following bookmarklet to your browser's bookmarks bar: -;; -;; javascript:location.href='org-protocol://webclip?url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title);void(0); -;; -;; To add the bookmarklet: -;; a. Create a new bookmark in your browser -;; b. Set the name to: Clip to Org (or your preference) -;; c. Set the URL to the JavaScript code above -;; d. Save it to your bookmarks bar for easy access -;; -;; 4. Click the bookmarklet on any web page to clip its content -;; -;; The clipped content will be added to the file specified by `webclipped-file` -;; under the "Webclipped Inbox" heading with proper formatting and metadata. -;; -;; Architecture: -;; - cj/--process-webclip-content: Pure function for content processing -;; - cj/org-protocol-webclip-handler: Handles URL fetching and capture -;; - cj/org-webclipper-EWW: Direct capture from EWW/W3M buffers -;; -;; Requirements: -;; - org-web-tools package -;; - Pandoc installed on your system -;; - Emacs server running (M-x server-start) +;; Content is converted to readable Org, normalized, and filed under the +;; configured webclip inbox heading. ;;; Code: diff --git a/modules/test-runner.el b/modules/test-runner.el index 50d4f7e40..48a2b09fe 100644 --- a/modules/test-runner.el +++ b/modules/test-runner.el @@ -6,69 +6,18 @@ ;; Layer: 2 (Core UX). ;; Category: C/L. ;; Load shape: eager. -;; Eager reason: the test keymap entry point and project-scoped runner state. -;; Top-level side effects: defines a test keymap, registers it under cj/custom-keymap. +;; Eager reason: registers the C-; t test runner entry point and state. +;; Top-level side effects: defines and registers cj/test-map. ;; Runtime requires: ert, cl-lib, keybindings. -;; Direct test load: yes (requires keybindings explicitly). +;; Direct test load: yes. ;; -;; This module provides a powerful ERT test runner with focus/unfocus workflow -;; for efficient test-driven development in Emacs Lisp projects. -;; -;; PURPOSE: -;; -;; When working on large Emacs Lisp projects with many test files, you often -;; want to focus on running just the tests relevant to your current work without -;; waiting for the entire suite to run. This module provides a smart test runner -;; that supports both running all tests and focusing on specific test files. -;; -;; WORKFLOW: -;; -;; 1. Run all tests initially to establish baseline (C-; t R) -;; 2. Add test files to focus while working on a feature (C-; t a) -;; 3. Run focused tests repeatedly as you develop (C-; t r) -;; 4. Add more test files as needed (C-; t b from within test buffer) -;; 5. View your focused test list at any time (C-; t v) -;; 6. Clear focus and run all tests before finishing (C-; t c, then C-; t R) -;; -;; PROJECT INTEGRATION: -;; -;; - Automatically discovers test directories in Projectile projects -;; (looks for "test" or "tests" under project root) -;; - Falls back to ~/.emacs.d/tests if not in a Projectile project -;; - Test files must match pattern: test-*.el -;; -;; SPECIAL BEHAVIORS: -;; -;; - Smart test running: Automatically runs all or focused tests based on mode -;; - Test extraction: Discovers test names via regex to run specific tests -;; - At-point execution: Run individual test at cursor position (C-; t .) -;; - Error handling: Continues loading tests even if individual files fail -;; -;; KEYBINDINGS: -;; -;; C-; t L Load all test files -;; C-; t R Run all tests (full suite) -;; C-; t r Run tests smartly (all or focused based on mode) -;; C-; t . Run test at point -;; C-; t a Add test file to focus (with completion) -;; C-; t b Add current buffer's test file to focus -;; C-; t c Clear all focused test files -;; C-; t v View list of focused test files -;; C-; t t Toggle mode between 'all and 'focused -;; -;; RECOMMENDED USAGE: -;; -;; While implementing a feature: -;; - Add the main test file for the feature you're working on -;; - Add any related test files that might be affected -;; - Use C-; t r to repeatedly run just those focused tests -;; - This provides fast feedback during development -;; -;; Before committing: -;; - Clear the focus with C-; t c -;; - Run the full suite with C-; t R to ensure nothing broke -;; - Verify all tests pass before pushing changes +;; Project-aware ERT runner with two modes: all tests or a focused file set. +;; Test roots come from Projectile projects, falling back to the config's tests +;; directory, and test files are discovered by the test-*.el convention. ;; +;; Commands under C-; t load tests, run all/focused tests, run the test at point, +;; and manage the per-project focus list. + ;;; Code: (require 'ert) diff --git a/modules/video-audio-recording.el b/modules/video-audio-recording.el index 1672529f7..fce3d9033 100644 --- a/modules/video-audio-recording.el +++ b/modules/video-audio-recording.el @@ -6,104 +6,19 @@ ;; Layer: 4 (Optional). ;; Category: O/D/S. ;; Load shape: eager. -;; Eager reason: none; registers a recording keymap, but device probing should -;; run only on command (command-loaded target). -;; Top-level side effects: defines cj/record-map and conditionally registers it -;; under C-; r. +;; Eager reason: none; records only on command, but registers C-; r at load. +;; Top-level side effects: defines cj/record-map and registers it when possible. ;; Runtime requires: system-lib, keybindings. -;; Direct test load: yes (requires keybindings explicitly). +;; Direct test load: yes. ;; -;; Desktop video and audio recording from within Emacs using ffmpeg. -;; Records from both microphone and system audio simultaneously, which -;; makes it suitable for capturing meetings, presentations, and desktop activity. -;; -;; Architecture: -;; - Audio recordings use ffmpeg directly with PulseAudio inputs → M4A/AAC -;; - Video recordings differ by display server: -;; - X11: ffmpeg with x11grab + PulseAudio → MKV -;; - Wayland: wf-recorder piped to ffmpeg for audio mixing → MKV -;; (wf-recorder captures the compositor, ffmpeg mixes in audio) -;; -;; Process lifecycle: -;; - Start: `start-process-shell-command` creates a shell running the -;; ffmpeg (or wf-recorder|ffmpeg) pipeline. Process ref is stored in -;; `cj/video-recording-ffmpeg-process' or `cj/audio-recording-ffmpeg-process'. -;; - Stop: SIGINT is sent to the shell's process group so all pipeline -;; children (wf-recorder, ffmpeg) receive it. We then poll until the -;; process actually exits, giving ffmpeg time to finalize the container. -;; - Cleanup: A process sentinel auto-clears the process variable and -;; updates the modeline if the process dies unexpectedly. -;; -;; Note: video-recordings-dir and audio-recordings-dir are defined -;; (and directory created) in user-constants.el -;; -;; Quick Start -;; =========== -;; 1. Press C-; r s to run quick setup -;; 2. Pick a microphone from the list -;; 3. Pick an audio output — [in use] shows which apps are playing -;; 4. Press C-; r a to start/stop audio recording -;; 5. Recording starts - you'll see 󰍬 in your modeline -;; 6. Press C-; r a again to stop (🔴 disappears) -;; -;; Device Setup -;; ============ -;; C-; r a automatically prompts for device selection on first use. -;; Device selection lasts for the current Emacs session only. -;; -;; Manual device selection: -;; -;; C-; r s (cj/recording-quick-setup) - RECOMMENDED -;; Two-step setup: pick a mic, then pick an audio output to capture. -;; Both steps show status: [in use], [ready], [available], [muted]. -;; Audio outputs also show which apps are playing through them. -;; Sorted: in use → ready → available → muted. -;; -;; C-; r S (cj/recording-select-devices) - ADVANCED -;; Manual selection: choose mic and monitor separately. -;; Use when you need different devices for input/output. -;; -;; C-; r d (cj/recording-list-devices) -;; List all available audio devices and current configuration. -;; -;; C-; r w (cj/recording-show-active-audio) - DIAGNOSTIC TOOL -;; Show which apps are currently playing audio and through which device. -;; Use this DURING a phone call to see if the call audio is going through -;; the device you think it is. Helps diagnose "missing one side" issues. -;; -;; Pre-Recording Validation -;; ======================== -;; Every time you start a recording, the system audio device is -;; validated automatically: -;; 1. If the configured monitor device no longer exists (e.g. -;; USB DAC unplugged), it's auto-updated to the current -;; default sink's monitor. -;; 2. If no audio is currently playing through the monitored sink, -;; a warning is shown in the echo area. Recording proceeds -;; without interruption — run C-; r s to see active streams. -;; -;; Testing Devices Before Important Recordings -;; ============================================ -;; Always test devices before important recordings: -;; -;; C-; r t b (cj/recording-test-both) - RECOMMENDED -;; Guided test: mic only, monitor only, then both together. -;; Catches hardware issues before they ruin recordings! -;; -;; C-; r t m (cj/recording-test-mic) -;; Quick 5-second mic test with playback. -;; -;; C-; r t s (cj/recording-test-monitor) -;; Quick 5-second system audio test with playback. -;; -;; To adjust volumes: -;; - Use =M-x cj/recording-adjust-volumes= (or your keybinding =r l=) -;; - Or customize permanently: =M-x customize-group RET cj-recording RET= -;; - Or in your config: -;; #+begin_src emacs-lisp -;; (setq cj/recording-mic-boost 1.5) ; 50% louder -;; (setq cj/recording-system-volume 0.7) ; 30% quieter +;; Starts and stops ffmpeg-backed audio/video recordings from Emacs. Audio +;; captures microphone plus system monitor; video uses x11grab on X11 and +;; wf-recorder piped into ffmpeg on Wayland. ;; +;; Recording processes are tracked in module variables, stopped with SIGINT so +;; containers finalize cleanly, and reflected in the modeline. Device selection +;; is session-local; quick setup and device tests live under C-; r. + ;;; Code: (require 'system-lib) -- cgit v1.2.3