aboutsummaryrefslogtreecommitdiff
path: root/modules
Commit message (Collapse)AuthorAgeFilesLines
* fix(calendar-sync): guard the hourly timer body against repeating signalsCraig Jennings46 hours1-10/+22
| | | | | | | | | - The sync timer body ran unguarded from an hourly run-at-time timer. - A signal in the timezone check or the sync fan-out errored every tick. - The same error, once an hour, indefinitely. - Wrapped the body in condition-case; an error is logged, not propagated. - Also demoted the timezone-change message to the silent log, like the module's other timer-path notices — an hourly timer shouldn't spam the echo area.
* fix(system-defaults): guard and cap the native-comp warning logCraig Jennings46 hours1-7/+22
| | | | | | | | - cj/log-comp-warning is :before-until advice on display-warning. - Its append-to-file was unguarded, so an unwritable log path signalled. - That signal propagated out and broke warning display for every comp notice. - Wrapped the write so a failure is swallowed and the warning stays suppressed. - The log also grew without bound; added a 512KB cap that resets it on overflow.
* fix(agenda-frame): keep the allowlist when org-agenda loads firstCraig Jennings47 hours1-2/+14
| | | | | | | | | | | | - The read-only shadow walk keeps a key only when the frame map binds it commandp. - It ran from with-eval-after-load partway up the file. - The day/week/redo handlers are defined further down. - With org-agenda already loaded, the walk fired before those defuns existed. - So it read them as non-commands and denied d/w/g/r — the keys the allowlist grants. - That is the normal startup order and every module reload. - Moved the walk to the end of the file, after all the handlers are defined. - A subprocess test loads org-agenda first and pins d/w/g/r surviving, t denied. - Retitled the t-test to assert the deny outcome, not the pre-walk unbound state.
* refactor(org-refile): name the two refile advices so they can be removedCraig Jennings47 hours1-14/+27
| | | | | | | | | - Both were anonymous lambdas advising org-refile and org-refile-get-targets. - An anonymous advice can't be advice-removed by reference. - So deleting one from source left a live daemon still running it. - Extracted both to named defuns and installed them remove-then-add. - Now each reloads to a single copy and is removable by reference. - Added unit tests for the target-visiting logic, which had no coverage.
* refactor: clear six byte-compile warnings across four modulesCraig Jennings47 hours4-11/+27
| | | | | | | | | | | | - org-agenda-frame declared two of its own functions with declare-function. - Same-file forward refs resolve at end of compile, so those were redundant. - Worse, the declared empty arglist overrode safe-redo's real (&optional frame). - That silently disabled arg-count checking on it; removed both declarations. - music-config and video-audio-recording referenced three vars before their defvars. - Added forward declarations so each compiles as a dynamic binding. - dashboard declared el special, which made the section macro's own binding shadow it. - Removed that declaration; el is the macro's lexical binding and resolves cleanly. - Declared wttrin, the last undefined-function reference in the launcher table.
* fix: correct four wrong behaviors and drop three dead code pathsCraig Jennings2 days7-101/+100
| | | | | | | | | | | | - yt-dlp downloads claimed completion when tsp had merely queued them. - A fresh machine opened org links in EWW, not Chrome. - ArchWiki search raised a raw error instead of the install hint. - The pre-commit hook kept running when its cd failed. - Removed a second device-grouping implementation nothing called. - Removed a redundant epub advice that ran on every file visit. - Removed a buffer-burying clause naming a mode Emacs doesn't define. - Moved the Hugo bindings onto the custom prefix map. - The ArchWiki docs path is now a variable, making it testable.
* fix(auto-dim): stop the minibuffer from re-dimming the window you leftCraig Jennings3 days1-1/+5
| | | | | | | - Opening the minibuffer dimmed whatever window you had just left. - Dimming follows selection, and the minibuffer takes selection. - auto-dim-other-buffers-dim-on-switch-to-minibuffer sat at its package default of t. - Set it to nil, so minibuffer entry leaves the dim state alone.
* fix: make the Full Agenda frame's default-deny actually denyCraig Jennings5 days1-0/+42
| | | | | | The frame's read-only policy leaned on a [t] catch-all, but a keymap's default binding never shadows an explicit binding in a lower-priority map. So every key org-agenda-mode-map binds sailed through the catch-all and could mutate source files from the "read-only" frame: t (todo), I (clock-in), k (capture), z (add-note), s (save-all), the C-c schedule/deadline/clock mutators, C-x C-s. Walk org-agenda-mode-map recursively on load and explicitly deny every sequence not on the frame's allowlist, so the catch-all's intent holds. Navigation, engage, refresh, d/w, and C-c C-o still work, and M-x is unaffected.
* feat(music): move single to 1, save to s, drop the stop keyCraig Jennings5 days1-8/+7
| | | | In the playlist buffer, single-track mode moves off s onto 1 and save moves off v onto s. The stop key (S) is gone, since SPC/pause already covers stopping. The Mode/Keys header legend follows, and v is now unbound. Stop is still reachable from the global music prefix (C-; m s).
* feat: add d/w day/week view toggle to the Full Agenda frameCraig Jennings5 days1-5/+37
| | | | The frame was locked to the 7-day span, with d and w denied as view-changes. The span is now a variable the F command reads. Org re-evaluates custom-command settings on every build and redo, so a day view survives the 5-minute refresh tick. d shows today's single day, w restores the 7-day view, and each spawn resets to 7 so a fresh frame opens at the default. The remaining date-navigation keys (y/f/b/j) stay denied to keep the frame today-anchored.
* fix: stop M-SPC / M-S-SPC escaping the Full Agenda frameCraig Jennings5 days1-0/+8
| | | | M-SPC and M-S-SPC (the ai-term agent-swap chords) are bound in the global map, so pressing them inside the read-only frame jumped to ai-term instead of being contained. The frame's [t] catch-all can't deny them: a keymap's default binding doesn't shadow an explicit binding in a lower-priority map. Deny both explicitly in the frame keymap.
* fix: bind g to refresh inside the Full Agenda frameCraig Jennings5 days1-1/+5
| | | | The frame's default-deny policy classed g as a view-change and denied it, so the muscle-memory refresh key printed the fixed-view message instead of rebuilding. Bind g to the same frame-scoped safe redo as r. C-M-<f8> stays the force-rescan.
* chore: raise company-idle-delay to 4 secondsCraig Jennings5 days1-1/+1
| | | | Completion rarely wants to fire on a pause, and the popup is a distraction mid-thought (especially in org-mode). A 4-second idle delay keeps it out of the way while still surfacing on a deliberate wait.
* refactor(elfeed): remove dead cj/extract-stream-urlCraig Jennings5 days1-24/+0
| | | | No production caller existed, and the v binding already plays entries through mpv, which resolves YouTube pages via its own yt-dlp hook internally, so the manual stream-URL extraction was fully superseded. Its tests go with it; the process-entries coverage stays.
* fix(system): resolve the locker at command time, not module loadCraig Jennings5 days1-2/+15
| | | | lockscreen-cmd baked (env-wayland-p) into a defvar at load, so a daemon started before WAYLAND_DISPLAY reached its environment froze the locker to slock and Lock failed silently on Wayland. The lock command now resolves per call, with lockscreen-cmd kept as an explicit override. Craig confirmed the fix over the decline option since it also makes the systemd unit path safe to revive.
* perf(ai-term): fetch the tmux session list once per launchCraig Jennings6 days3-8/+17
| | | | The launch path spawned tmux list-sessions up to three times: in the project picker's sorting, in the launcher's fresh check, and again inside show-or-create. The list is now fetched once and threaded through; the cycling path still fetches its own.
* refactor(case): flatten title-case-region into focused helpersCraig Jennings6 days1-48/+64
| | | | The command nested six levels deep. The title-case vocabulary (reset chars, separators, minor words) is now defconsts, and bounds resolution, last-word location, and the per-word capitalization step are their own functions. The 34 existing title-case tests pin the behavior unchanged.
* perf(host-env): try cheap timezone methods before the zoneinfo scanCraig Jennings6 days1-9/+10
| | | | The content-comparison scan reads hundreds of zoneinfo files and ran first on every call. TZ, /etc/timezone, and the symlink target are O(1) and answer on almost every system; the scan is now the last resort for a copied /etc/localtime. Verified the symlink and scan agree on this machine.
* refactor(text-enclose): extract the shared replace-region tailCraig Jennings6 days1-28/+19
| | | | Four commands repeated the bounds/delete/goto/insert triad; cj/--replace-region-or-buffer now owns it. The replacement is computed before the delete, preserving the old error behavior (a failed transform leaves the buffer untouched).
* refactor(comments): extract shared comment-syntax resolutionCraig Jennings6 days1-36/+30
| | | | The comment-start/comment-end resolution was copied into six command wrappers. One cj/--comment-read-syntax now owns it; the block-banner wrapper keeps its own block-specific prompt.
* fix(dev-fkeys): run javascript test files through the npx runnerCraig Jennings6 days1-2/+3
| | | | The language detector classifies js/jsx and the test-file detector recognizes JS tests, but the dispatch had no javascript arm, so C-F6 on a JS test errored though the typescript npx path runs it fine. javascript now shares that arm.
* fix(calendar): skip short months for plain monthly-on-the-31st rulesCraig Jennings6 days1-2/+18
| | | | The stepper kept day-of-month verbatim, so Jan 31 stepped to Feb 31 and encode-time normalized it into a phantom Mar 3 occurrence. Plain monthly rules now advance to the next month that has the day, per RFC 5545.
* fix(comments): render padded dividers at LENGTH exactlyCraig Jennings6 days1-0/+5
| | | | available-width omitted the doubled semicolon and the space after comment-start that the emit path adds, so dividers rendered LENGTH+2 (elisp) or LENGTH+1 wide. The budget now mirrors every term min-length already counts.
* fix(music): queue all dired-marked files and de-anonymize header adviceCraig Jennings6 days1-5/+16
| | | | | | cj/music-add-dired-selection gated dired-get-marked-files behind use-region-p, so files marked with m fell to the single-file branch and only the point file was queued. dired-get-marked-files already honors marks, a region, or point on its own. The header-refresh advice on the four EMMS toggles was an anonymous lambda, which can't be advice-removed and stacked a copy on every :config reload. It's now a named function installed remove-then-add.
* fix(undead-buffers): keep C-u on wrapper commands from spamming the undead listCraig Jennings6 days1-5/+11
| | | | The delegated cj/kill-buffer-or-bury-alive reads current-prefix-arg, so a prefixed wrapper call took the add-to-undead-list branch for every buffer: nothing killed, list spammed. The four wrappers now bind the prefix to nil around the delegate.
* fix(dashboard): make the bookmarks override realCraig Jennings6 days1-24/+33
| | | | The top-level defun was clobbered when use-package reloaded dashboard-widgets, so the override never ran. Deferring it kept it alive but exposed a second bug: dashboard-insert-section is a macro, unknown at module compile time, so the body compiled as a function call and crashed void-variable at render. The override now registers after dashboard-widgets and compiles with the macro known.
* fix(org-roam): declare capture-templates special for immediate insertCraig Jennings6 days1-0/+4
| | | | Without the defvar, the byte-compiled let-binding in cj/org-roam-node-insert-immediate is a dead lexical binding and :immediate-finish never reaches org-roam-node-insert, so the immediate insert opened a capture buffer.
* fix(jumper): handle empty completing-read input without crashingCraig Jennings6 days1-1/+6
| | | | An unmatched choice made the assoc lookup nil, which crashed the index arithmetic with wrong-type-argument. The jump prompt now gives a user-error and the remove prompt cancels.
* fix(external-open): guard looping video open behind executable-findCraig Jennings6 days1-0/+5
| | | | The command fires via the find-file advice, so visiting a video without mpv on PATH threw an opaque call-process error mid-visit.
* fix(slack): friendly error on reaction command before slack loadsCraig Jennings6 days1-1/+4
| | | | slack-current-buffer is declared but void until slack.el loads, so a cold C-; S ! signaled void-variable instead of the not-in-a-Slack-buffer message.
* fix(flyspell): escape the + so org src blocks are actually skippedCraig Jennings6 days1-2/+4
| | | | The skip entry used "#+" (one-or-more #), which matches no real begin_src line, so ispell spell-checked inside every org code block.
* refactor(go): pin grammar revision via struct accessor, not raw indexCraig Jennings6 days1-2/+3
|
* refactor(mu4e): collapse dead completion conditionalCraig Jennings6 days1-6/+3
|
* refactor(coverage): replace double-negative empty guard with whenCraig Jennings6 days1-1/+1
|
* refactor(epub): drop unused col-px binding in nov-center-imagesCraig Jennings6 days1-2/+1
|
* fix(erc): declare erc-server-process specialCraig Jennings6 days1-0/+1
|
* fix(auth): declare plstore-open for the byte-compilerCraig Jennings6 days1-0/+1
|
* fix(dwim-shell): correct flip-vertically docstringCraig Jennings6 days1-1/+1
|
* feat(agenda): suspend auto-dim while the agenda frame is openCraig Jennings6 days1-0/+25
| | | | The refresh tick's selection swing marks the working window non-selected, and auto-dim's debounced dim lands after the tick, so the working frame visibly dimmed every five minutes. Spawn now turns auto-dim-other-buffers-mode off (remembering it was on) and closing the frame restores it. A spawn with auto-dim already off touches nothing. It also keeps the standing agenda fully lit instead of dimmed-when-unfocused.
* fix(agenda): hide the refresh tick's selection flickerCraig Jennings6 days1-2/+14
| | | | The rebuild takes a second or two, and for its whole duration the agenda window was the selected window, so the cursor visibly went hollow in the working frame on every tick. It read as focus theft, though no focus function ever ran. The tick now inhibits redisplay (the synchronous rebuild blocks Emacs anyway, so this costs nothing) and restores selection before redisplay resumes. A tick that would fire during an active minibuffer is skipped.
* fix(agenda): repair the refresh tick, tighten the gutter, allow point motionCraig Jennings6 days1-4/+27
| | | | | | | | Every 5-minute refresh failed. The F command's general settings carried (org-agenda-sticky t), and those settings are baked into the buffer's series-redo-cmd and re-applied on each redo. With the buffer already existing, org-agenda-use-sticky-p turned true mid-redo and org-agenda-prepare threw 'exit ("use r to refresh") to a catch that doesn't exist inside org-agenda-redo. I removed sticky from the command settings (the spawn wrapper still binds it, which is where the buffer gets its name) and kept the redo path free of sticky, since org-agenda-redo handles the in-place rebuild itself. Verified with a real tick against a live frame: rebuild succeeds, the failure banner clears, the latch resets. The wide gutter between the source column and the item was the global agenda prefix format's 25-char category pad. The F view now sets its own format with a 10-char pad. C-a hit the deny catch-all. I allowlisted read-only point motion (C-a, C-e, C-f, C-b) and isearch (C-s, C-r).
* fix(agenda): keep the agenda frame a single full-height agenda windowCraig Jennings6 days1-4/+17
| | | | | | | | The frame spawned with the working buffer in its top quarter and the agenda below at 75%. The sticky setting inside the F custom command applies too late to name the buffer, so it rendered as plain *Org Agenda*, and that name matches the 0.75 below-selected display rule in org-agenda-config.el, which split the brand-new frame. I bind org-agenda-sticky and current-window dynamically around the render, so the buffer is *Org Agenda(F)* (no display rule matches it) and it takes the frame's sole window. A delete-other-windows after the render is the belt in case any future rule still splits. The frame is also named "Full Agenda" now so it's recognizable at a glance and WM rules can target it.
* fix(agenda): make C-x C-c close the agenda frame, not the daemonCraig Jennings6 days1-0/+5
| | | | The catch-all denied it before, and letting the global through would be worse: save-buffers-kill-terminal on a make-frame frame has no client to close, so it kills the daemon. Inside the frame the gesture now runs the frame close.
* fix(agenda): stop the frame's catch-all from swallowing input machineryCraig Jennings6 days1-18/+45
| | | | | | | | The default-deny [t] binding intercepted far more than Org commands. switch-frame events hit the deny handler, so every focus change into or out of the frame spammed the read-only message and broke frame switching. Mouse wheel, mouse-1 clicks, and the help prefix were dead. And S-<f8>/C-M-<f8> were never bound in the mode map, so the frame's own toggle couldn't close it from inside. I punched the machinery through the catch-all (an explicit nil shadows the [t] default in the same map, so those events fall through to their global bindings) and bound the two frame controls per the spec's allowlist. Two redo-lifecycle bugs rode along, both from org-agenda-mode's kill-all-local-variables: the buffer-local kill-buffer-hook was stripped on the first refresh tick (killing the buffer would orphan the frame), and the failure banner was held in a buffer-local var while its overlay survives erase-buffer, so a banner could never be removed after a later success. The finalize re-enable now re-adds the hook, and the banner is tagged with an overlay property and found by scanning.
* fix(agenda): spawn the agenda frame tiled, not compositor-fullscreenCraig Jennings6 days2-13/+21
| | | | I dropped (fullscreen . fullboth) from the spawned frame so a tiling WM places it side by side with the working frame. "Fullscreen" was the wrong word for the intent: a normal frame at its full tiled position, not one covering the whole output. The engage-routing and focus logic are unchanged and matter more now, since a task opens in the adjacent working pane.
* feat(agenda): add S-<f8> dedicated fullscreen agenda frameCraig Jennings6 days2-3/+640
| | | | | | | | I added a standing agenda surface in its own fullscreen frame of the daemon, placeable on its own workspace while the working frames stay untouched. S-<f8> spawns, raises, or closes it. The force-rescan moves to C-M-<f8>. It shows a today-anchored seven-day view and refreshes every five minutes through org-agenda-redo, so the now-line and synced events stay current without re-scanning the file list. A default-deny minor mode keeps it read-only: only navigation, the engage keys (routed to the working frame), and the frame's own controls are allowed. A failed redo falls back to the last-good snapshot with cloned markers, so the frame is never blank or unrestricted. I made it a frame of the daemon rather than a second process, so it shares the live state (calendar-sync, edits, the now-line). There's no startup auto-open, and the Hyprland-managed-window variant is a vNext once this proves out.
* feat(fontaine): rename Coding to Coding M, add Coding L at 14ptCraig Jennings6 days2-3/+8
| | | | | The Berkeley Mono code ladder is now Coding XS (11pt), Coding M (13pt), Coding L (14pt), and Coding XL (16pt).
* feat(ai-term): M-SPC cycles attached agents, M-S-SPC cycles allCraig Jennings6 days3-29/+74
| | | | | | | | | | | | M-SPC now steps only through attached agents (the ones with a live on-screen buffer), so the fast chord stays among what's already up. M-S-SPC steps through all active agents and attaches a detached tmux session when it lands on one, which is what M-SPC used to do. I moved the shared step logic into cj/--ai-term-step-among and added cj/--ai-term-attached-agent-dirs to filter the queue to attached buffers. I bound both chords globally and in eat-semi-char-mode-map so they work from inside an agent buffer. C-; a n keeps cycling all.
* refactor: drop unreachable nil after user-error in recording checksCraig Jennings6 days1-4/+2
|
* feat: add workflow font profilesCraig Jennings7 days4-114/+280
| | | | | | I replaced the mixed Fontaine presets with seven named profiles that persist across restarts. The mode line, echo area, and minibuffer stay in Berkeley Mono. Nov applies the shared Reading profile inside each EPUB buffer without changing the global selection.