aboutsummaryrefslogtreecommitdiff
path: root/modules
Commit message (Collapse)AuthorAgeFilesLines
* refactor(calibredb-epub): extract nov re-render and centering helpersCraig Jennings18 hours1-18/+31
| | | | | | | Lift the render-preserving-position block and the margin/fringe block out of cj/nov-update-layout into cj/nov--rerender-preserving-position and cj/nov--center-in-window, dropping its nesting. Fold the thrice-repeated #E8DCC0 sepia literal in cj/nov-apply-preferences into one local binding.
* refactor(elfeed): extract HTML-entity decoder, drop leftover DEBUG loggingCraig Jennings20 hours1-18/+12
| | | | cj/youtube-to-elfeed-feed-format hand-decoded an og:title with six sequential replace-regexp-in-string calls; extract cj/--decode-html-entities (alist-driven, & first) and call it. Also remove the leftover DEBUG cj/log-silently instrumentation from cj/extract-stream-url. Behavior unchanged; adds coverage of the decoder.
* refactor(prog-webdev): use the shared format-region helperCraig Jennings20 hours1-26/+1
| | | | prog-webdev carried cj/--webdev-format-region, a third byte-identical copy of the format-region helper already extracted to system-lib in the prog-json/prog-yaml dedup. Drop it and call cj/format-region-with-program (system-lib is already required). Behavior unchanged; the existing format tests cover it.
* refactor(prog-general): dedup the deadgrep search tail, lift its helpersCraig Jennings20 hours1-13/+21
| | | | cj/deadgrep-here and cj/deadgrep-in-dir repeated the same normalize-directory + read-term + invoke-deadgrep tail. Lift cj/deadgrep--initial-term out of :config and add cj/--deadgrep-run for the shared tail; each command resolves its root then delegates. Adds coverage for the term seeding and the run helper.
* refactor(prog-general): lift cj/find-project-root-file out of :configCraig Jennings20 hours1-14/+13
| | | | The pure project-root file finder lived inside the projectile use-package :config, so it was unreachable under make test. Move it to top level (its forward declaration already existed); cj/open-project-root-todo and cj/project-switch-actions still call it. Adds unit coverage for string regexps, rx forms, no-match, and no-project.
* refactor(font-config): lift frame/icon helpers out of :configCraig Jennings20 hours1-36/+39
| | | | cj/apply-font-settings-to-frame, cj/cleanup-frame-list (inside with-eval-after-load 'fontaine) and cj/maybe-install-all-the-icons-fonts (inside all-the-icons :config) carried real branching but were unreachable under make test. Move all three (and the cj/fontaine-configured-frames state) to top level; the :config/eval-after-load blocks keep only the hook wiring. Adds declare-function for the package calls and coverage of the apply/cleanup/install branches.
* refactor(erc): lift cj/erc-generate-buffer-name out of :configCraig Jennings20 hours1-9/+9
| | | | The buffer-name function lived inside the erc use-package :config, so it was unreachable under make test (no package-initialize). Move it to top level; :config keeps the erc-generate-buffer-name-function setq. Adds unit coverage for the server-and-channel, server-only, and missing-piece cases.
* refactor(mousetrap): extract per-category event-binding loopCraig Jennings20 hours1-16/+20
| | | | mouse-trap--build-keymap-1 nested its event-binding cond/dolists five deep. Extract mouse-trap--bind-events-to-ignore (spec prefixes map); build-keymap-1 now just walks the categories and delegates the binding. Adds coverage for the wheel and click-event paths.
* refactor(chrono-tools): extract tmr sound-file helpers, flatten the commandCraig Jennings20 hours1-15/+19
| | | | cj/tmr-select-sound-file nested cond/let five deep, mixing the current-sound lookup, the completing-read, the setq, and the message. Extract cj/tmr--current-sound-name and cj/tmr--apply-sound-file (the testable parts) and flatten the inner conds to ifs. The command keeps the prefix-arg/no-dir/no-files guards and the prompt. Adds coverage for both helpers.
* refactor(jumper): extract marker-traversal and location-candidates helpersCraig Jennings20 hours1-32/+41
| | | | jumper--location-exists-p and jumper--format-location both opened a marker with the same save-current-buffer/set-buffer/save-excursion/goto-char dance; jumper-jump-to-location and jumper-remove-location shared a verbatim candidate-list cl-loop. Extract jumper--with-marker-at (index fn) and jumper--location-candidates; the four callers delegate. Adds direct coverage of the candidate list.
* refactor(modeline): extract the clickable-segment keymap builderCraig Jennings20 hours1-11/+13
| | | | The buffer-name, vc, and major-mode segments each hand-rolled the same make-sparse-keymap + define-key [mode-line mouse-1/3] construction. Extract cj/--modeline-click-map (mouse-1 &optional mouse-3); the three segments call it. Adds coverage for the one- and two-button cases.
* refactor(ai-config): extract gptel model-apply step, drop dead branchCraig Jennings20 hours1-8/+16
| | | | cj/gptel-change-model applied the selection inline (scope dispatch + message) and re-checked (stringp model) on a value already interned to a symbol. Extract cj/--gptel-apply-model-selection (scope backend model backend-name), which sets the vars globally or buffer-locally and returns the message; the dead stringp branch is gone. Adds direct coverage of both scopes.
* refactor(ai-conversations): reuse the autosave-active predicate in the hooksCraig Jennings20 hours1-8/+2
| | | | cj/gptel--autosave-after-send and cj/gptel--autosave-after-response re-inlined the four-clause "should we autosave?" boolean that cj/gptel--autosave-active-p already encapsulates. Call the helper instead (after-send keeps its extra autosave-on-send flag). Behavior unchanged; one predicate to maintain.
* refactor(org-agenda): extract the agenda base-file listCraig Jennings21 hours1-5/+10
| | | | The fixed base list (inbox, schedule, and the three calendars) was spelled out as a literal in cj/--org-agenda-scan-files, cj/todo-list-single-project, and the chime initializer. Extract cj/--org-agenda-base-files so adding a calendar source is a one-place change; the single-project view prepends its todo.org with cons. Adds a test for the helper's contents and order.
* refactor(mail-config): build the account-nav keymaps from one templateCraig Jennings21 hours1-18/+34
| | | | The cmail/dmail/gmail navigation maps were three near-identical defvar-keymap blocks differing only by maildir prefix, with the unread/flagged/large query clauses repeated in each. Add cj/--mail-account-search-queries (account -> the four search strings) and cj/--mail-make-account-map (builds the keymap), wrapped in eval-and-compile so org-msg's :preface can call the builder during byte-compilation. The three maps become one-line builder calls. Adds direct coverage of the query strings and the per-account closures.
* refactor(org-capture): extract the find-or-create-top-heading blockCraig Jennings21 hours1-25/+24
| | | | cj/org-capture--goto-file-headline, cj/--org-capture-goto-open-work, and cj/--org-capture-goto-exact-headline each repeated the same positioning block: search from point-min, jump to the heading on a match, else append it at end of buffer and back up. Extract cj/--org-find-or-create-top-heading taking the search regexp and the heading line; the three sites delegate. Behavior unchanged; adds direct coverage of the helper with a plain regexp.
* docs(custom-ordering): correct point-position note on replace-region helperCraig Jennings21 hours1-1/+1
|
* refactor(custom-text-enclose): extract the region-or-word dispatchCraig Jennings21 hours1-48/+30
| | | | cj/surround/wrap/unwrap-word-or-region each repeated the same skeleton: target the active region, else the word at point, else show a message; then delete and re-insert the transformed text. Extract cj/--enclose-region-or-word, which takes the transform as a function and the no-target message, so each command reads its prompts then delegates. Behavior and messages unchanged; adds direct coverage of the dispatch helper.
* refactor(custom-datetime): generate the six inserters from one macroCraig Jennings21 hours1-33/+28
| | | | The six cj/insert-* commands were identical except their format variable and a one-word docstring noun. Replace them with a cj/--define-datetime-inserter macro and six table-style calls; the format defvars and the keymap are unchanged. Adds a test asserting all six stay interactive commands.
* refactor(custom-ordering): dedupe region guard, replace tail, and ↵Craig Jennings21 hours1-56/+46
| | | | | | arrayify-python Extract cj/--ordering-validate-region (the start>end guard copy-pasted across all seven pure helpers) and cj/--ordering-replace-region (the delete-region + insert tail repeated in every interactive command). Alias cj/arrayify-python to cj/arrayify-json, which it duplicated verbatim, leaving both keybindable. Behavior unchanged; adds direct Normal/Boundary/Error coverage for the two new helpers.
* refactor: extract shared format-region helper into system-libCraig Jennings21 hours3-54/+32
| | | | prog-json and prog-yaml each carried a byte-identical cj/--<lang>-format-region that runs a formatter over the buffer via call-process-region and replaces it on exit 0. Hoist it to system-lib as cj/format-region-with-program with a generic output buffer, and point both formatters at it. Adds the first direct unit coverage of the helper (Normal, Boundary, Error).
* refactor: remove dead wrappers and commented-out blocksCraig Jennings21 hours6-33/+1
| | | | Drop cj/apply-browser-choice (browser-config) and cj/load-fallback-theme (ui-theme), orphaned wrappers with no caller that just duplicated logic the live paths already inline, plus their tests. Delete commented-out blocks: a duplicate contact capture template (org-contacts-config), a disabled personal-info-dir :init (help-config), a stale TODO setq (org-config), and an old commented regex (test-runner).
* fix(windows): shrink the pull-away reveal to the minimum window heightCraig Jennings22 hours1-1/+6
| | | | minimize-window floors at window-min-height (4 lines), leaving roughly a 10% reveal. Bind window-min-height to 1 around it so the reveal opens at the ~2-line floor and the current window keeps almost the whole frame before the windsize arrows take over.
* fix(windows): keep the pulled-away window on the arrow's edgeCraig Jennings22 hours1-19/+27
| | | | The sole-window pull split toward the arrow at 50/50, so a fullscreen terminal jumped above the revealed buffer at half height. Now the reveal opens on the opposite side and is minimized to a sliver, so the current window keeps the arrow's edge near-full and the sticky windsize arrows shrink it step by step, matching the feel of resizing an existing split.
* feat(windows): pull a window away from a sole window with C-; b + arrowCraig Jennings22 hours1-5/+33
| | | | When the selected window fills the frame there is no divider to resize, so the arrow now splits toward its direction with the previous buffer and the original window shrinks from that edge. Multi-window resize is unchanged.
* feat(dirvish): bind d to duplicate, D to guarded force-deleteCraig Jennings22 hours1-2/+33
| | | | Drop delete-to-trash. d now duplicates the file at point. D force-deletes the marked files via sudo rm -rf behind a yes-or-no-p that names the targets, and reports success only when rm exits 0.
* feat(windows): dock companion panels by a shared min-column ruleCraig Jennings30 hours4-26/+121
| | | | | | The F9 agent always docked as a right-side column on a landscape frame. On this 138-column frame that left ~68-column panes, too cramped to read code and the agent side by side. The F12 terminal and F10 playlist hardcoded a bottom split with no width-aware path. I added cj/preferred-dock-direction and the cj/window-dock-min-columns defcustom (default 80) to the window-geometry lib: dock side-by-side only when the narrower pane keeps at least the minimum width, otherwise stack below. All three toggles now route through it. F9 drops its pixel-aspect rule. F12 and F10 gain a right-column width default and become adaptive. F10 keeps width and height size memory in separate vars so a resize on one axis doesn't leak to the other.
* refactor(ui): remove buffer-state coloring of the buffer nameCraig Jennings2 days3-51/+5
| | | | The modeline colored the buffer name by write and modification state (red read-only, green modified, gold overwrite) through a classifier in user-constants.el. I removed it, the same way the matching cursor coloring was removed earlier for being more confusing than useful. The classifier had no other live user, so it and its two test files go with it. The buffer name now renders in the normal mode-line color.
* fix(term): pin ghostel to pre-regression 0.33.0 to stop the crashCraig Jennings3 days1-0/+15
| | | | | | | | ghostel 0.35.0-0.35.2 hard-crash the whole Emacs process when a terminal buffer is displayed. The native PTY path was reworked to spawn worker threads. On Linux/glibc a SIGSETXID handler then calls malloc while the main thread holds the arena lock, so opening an agent terminal takes the whole editor down (upstream #422, with #423 the macOS recursive-lock variant). Reproduced down to a plain M-x ghostel in a GUI frame, so it's not ai-term-specific. Hold ghostel at the 0.33.0 build (ghostel-20260604.2049), which predates that rework. :ensure is satisfied by the installed 0.33.0 directory and won't upgrade it. The use-package block carries the rationale and a do-not-upgrade guard so it isn't bumped back into the crash before upstream ships a fix. Also set ghostel-module-auto-install to download so the native module installs without the interactive prompt.
* feat(ui-navigation): split from the dashboard opens scratch, not the dashboardCraig Jennings5 days1-4/+19
| | | | C-x 2 / C-x 3 already show the dashboard in the new window while point stays put. The one dead spot was splitting from the dashboard itself, which put the dashboard in both panes. Now the new window shows *scratch* when the current buffer is the dashboard, and the dashboard everywhere else. I pulled the choice into a pure predicate (cj/--split-from-dashboard-p) and a companion helper, both tested.
* refactor(system-utils): remove the *scratch* background tintCraig Jennings5 days1-29/+2
| | | | I dropped the buffer-local face remap that lightened the *scratch* background 5% above the theme default. Scratch now uses the plain theme background like every other buffer. The startup hook still moves the cursor to end-of-scratch. Only the tint call, its two helpers, the defcustom, the color require, and the now-orphaned test go.
* feat(keybindings): mirror the C-; command family under C-c ;Craig Jennings5 days1-0/+4
| | | | C-; is GUI-only: terminals can't encode Control-semicolon, so the whole custom command family (calendar, AI, Slack, org, pearl, jump, and the rest) was unreachable in a terminal frame (emacs -nw, emacsclient -nw, or Emacs inside vterm/tmux). I bound the single cj/custom-keymap under C-c ; alongside C-;, so the same leaf keys reach the identical map in both GUI and TTY with no relearning and no per-module edits. C-c is the standard user prefix and always TTY-encodable. I audited every leaf key in the family and they're all TTY-safe (letters, digits, punctuation, SPC, and arrow keys), so nothing needed remapping.
* fix(mail): theme mu4e buffers via a shared font-lock exclusionCraig Jennings5 days3-1/+31
| | | | mu4e paints its header lines, main menu, and view headers with manual `face' text properties. Global font-lock stripped them, so the buffers rendered unthemed, the same failure the dashboard hit. I extracted the dashboard's one-off exclusion into a shared, additive cj/exclude-from-global-font-lock helper in system-lib and repointed the dashboard to it. Then I excluded mu4e-headers-mode, mu4e-main-mode, and mu4e-view-mode. The view body renders through gnus's own washing rather than font-lock, so excluding it is safe.
* feat(dashboard): per-filetype icons on the list itemsCraig Jennings5 days1-0/+1
| | | | I enabled dashboard-set-file-icons so the project, bookmark, and recent-file rows show nerd-icons file icons, colored per filetype. They render now that the dashboard is out of global font-lock, which was stripping the icon faces too. Bookmarks fall back to a generic icon since there's no filetype to map.
* fix(dashboard): exclude dashboard-mode from global font-lockCraig Jennings5 days1-0/+9
| | | | | | The dashboard banner title and section headings render in the default face instead of their theme colors. The faces are defined correctly. Global font-lock fontifies the dashboard buffer and strips the `face' text properties dashboard sets by hand: it owns `face' and clears props it didn't apply. Items and the navigator survive because their color rides a dashboard-items-face overlay, which font-lock leaves alone. Excluding dashboard-mode from global font-lock keeps the banner and heading faces. I set it at top level so it applies regardless of the use-package body.
* fix(ai-config): intern model in gptel-switch-backend (modeline hang)Craig Jennings5 days1-1/+11
| | | | | | cj/gptel-switch-backend set gptel-model to the raw completing-read string. gptel's modeline code calls symbolp on gptel-model and signals wrong-type-argument on a string, which surfaces as a redisplay hang (reachable from C-; a B). The sibling command cj/gptel-change-model already interns. This one didn't. I added a pure cj/gptel--model-to-symbol helper (mirroring cj/gptel--model-to-string) and route the model through it before the setq. The existing switch-backend test asserted the buggy string value. It now asserts a symbol plus an explicit symbolp guard.
* feat(system-utils): tint the *scratch* background a shade lighterCraig Jennings5 days1-2/+29
| | | | A buffer-local face remap lightens the *scratch* default background by cj/scratch-background-lighten percent (default 5) so it reads as the scratch buffer, applied on emacs-startup-hook. The colour math is display-dependent (verified live); the pure helper's guard contract is unit-tested.
* fix(vertico): Page-Up/Down scroll the candidate list, not historyCraig Jennings5 days1-7/+11
| | | | <next>/<prior> weren't bound in vertico-map, so in a long completing-read they fell through and selected-then-dismissed the list. Bind them to vertico-scroll-up / vertico-scroll-down.
* fix(custom-comments): heavy-box interiors are valid commentsCraig Jennings5 days1-37/+47
| | | | The heavy-box empty and text lines began with a bare decoration char, so in line-comment languages (elisp, Python) C-; C h injected syntax-breaking lines. Prefix the interiors with the comment char and suffix them like cj/--comment-box does. Add the missing min-length guard so small or negative widths error cleanly instead of failing inside make-string. Updated the two characterization assertions to the corrected output.
* fix(dirvish): mark-all-visible no longer skips every other fileCraig Jennings5 days1-16/+8
| | | | dired-mark advances point itself, so the loop's extra forward-line skipped every other file (and could mark a directory). Use dired-get-filename + file-directory-p with an if/else: a marked file line advances once via dired-mark, non-file/directory lines advance manually. Replaces the regex line predicate (retired with its mock test) with a real-Dired marked-count test.
* refactor(ui-config): drop buffer-state cursor coloringCraig Jennings5 days1-45/+4
| | | | A cursor that changed color by buffer state was confusing. Remove cj/set-cursor-color-according-to-mode, its two cache defvars, and the post-command / server-after-make-frame hook registrations; the cursor now uses the theme cursor face. The cj/buffer-status-state / cj/buffer-status-color classifier stays in user-constants.el for the modeline buffer-name indicator. Delete the cursor-function integration test; keep the classifier tests.
* feat(dashboard): add a Signal launcherCraig Jennings5 days1-3/+4
| | | | Signal joins the dashboard launchers on key S (icon nf-md-message), opening cj/signel-message. Row sizes go 4-4-3-3 so Slack, Linear, and Signal share the last navigator row.
* feat(ai-term): dock the agent window by frame aspect ratioCraig Jennings5 days1-14/+22
| | | | The agent window now docks from whichever edge conserves more space, chosen at display time: right on a landscape frame, bottom on a square or portrait one, replacing the host (laptop/desktop) branch. cj/--ai-term-direction-for-aspect is the pure decision; default-size pairs the width or height fraction with it.
* fix(ui-navigation): undo-kill-buffer skips open files via equalCraig Jennings5 days1-1/+4
| | | | The visited-file filter used delq, comparing expand-file-name strings by eq, so an already-open file was never removed from the candidates (the skip logic was dead). Use delete (equal). Adds a test with the open file at the head of the list, where the eq/equal difference actually shows.
* feat(dashboard): g refreshes, Telegram moves to G, F1 refreshes on showCraig Jennings5 days1-1/+8
| | | | | - g on the dashboard now runs dashboard-refresh-buffer (the dired/magit convention) instead of opening Telegram. Telegram moves to G in the launcher table. - cj/dashboard-only (F1) refreshes before showing, so re-displaying the dashboard always lands on fresh content.
* feat(ui-navigation): C-x 2/3 show the dashboard in the new windowCraig Jennings5 days1-0/+28
| | | | Splitting with C-x 2 or C-x 3 now shows *dashboard* in the freshly created window and keeps point in the original, instead of mirroring the current buffer. cj/--split-show-buffer does the placement; cj/--dashboard-buffer fetches or opens the dashboard without disturbing windows.
* fix(eshell): flatten visual-commands, wire xterm-color correctlyCraig Jennings5 days1-14/+20
| | | | | - eshell-visual-commands is a flat string list, but add-to-list pushed the whole list as one element, so lf/ranger/htop/top never opened in a visual terminal. dolist the strings instead. (visual-subcommands/options are alists and were already correct.) - The xterm-color before-prompt hook was registered as eshell-before-prompt-hook, which use-package turned into eshell-before-prompt-hook-hook and never ran. Use the real hook name, and actually install xterm-color-filter into eshell-preoutput-filter-functions (dropping eshell-handle-ansi-color) so color output is interpreted.
* fix(prog-go): autoload gofmt so C-; f works under go-ts-modeCraig Jennings5 days1-0/+4
| | | | .go opens the built-in go-ts-mode, so nothing triggered the go-mode package: gofmt was never autoloaded (C-; f signalled void-function) and the :config setting goimports + exec-path never ran. Add :commands (gofmt) so the first format pulls go-mode and its config.
* fix(system-defaults): guard server-start and custom-file against batchCraig Jennings5 days1-3/+8
| | | | A raw module load under --batch started a server and dropped a throwaway custom-file temp on every run; the suite only passed because a testutil stubbed the server. Guard both with (unless noninteractive ...), the established pattern here. Adds a batch-load test for the custom-file guard.
* fix(auth-config): guard gpg-connect-agent, require user-constants at runtimeCraig Jennings5 days1-4/+6
| | | | | - The bare call-process to gpg-connect-agent in :config aborted init with file-missing on a machine without the binary. Guard it with cj/executable-find-or-warn. - user-constants was required only eval-when-compile, but authinfo-file is read at load time, so a standalone .elc load failed. Require it at runtime.