| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
INTEGRATION_TESTS globbed test-integration-%.el through $(wildcard ...), which
takes a shell glob where % is a literal character, not a pattern. It expanded to
nothing, so test-all skipped the integration phase and still printed "All tests
complete". Fourteen files never ran, for as long as the variable has existed.
The % is right one line up, because filter-out does take make patterns.
The glob is now test-integration-*.el, and the counts add up: 597 unit + 14
integration = the 611 test files on disk.
Turning the gate on surfaced five failures, none of them in production code.
Four were rotting fixtures. parse-ics drops events outside a rolling window of
today minus calendar-sync-past-months to plus future-months, and four tests fed
it dates pinned to November 2025 or February 2026. They passed when written and
began failing once the window slid past them. Their neighbours survived for two
reasons: some hand their fixture to parse-event, which applies no window, and
the weekly ones use unbounded RRULEs that keep generating into the window
however old the DTSTART is. The fixtures now build dates relative to now, which
is what the timezone file's own helper already did.
The fifth was a real regression, caught five months late. The recording toggle
test asserted on a fixture device and got whatever hardware is plugged into the
developer's machine. cj/recording-get-devices runs --validate-system-audio,
which shells to pactl, finds the fixture device isn't a real source, and
auto-fixes the configured device to the default sink's monitor. The test mocked
start-process-shell-command but not shell-command-to-string, so validation
reached the real machine. It passes at 5bdd3420~1 and fails at 5bdd3420, the
commit that added that validation in February.
I faked pactl at the shell boundary rather than stubbing --validate-system-audio
out, so the validation logic still runs, against a fixture machine.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
format-timestamp built its date from the start and took only the hour and
minute from the end, so the end date was thrown away. A conference running Jul
20 09:00 to Jul 23 17:00 produced <2026-07-20 Mon 09:00-17:00>, byte for byte
the same timestamp as a same-day meeting, and the agenda showed it on the first
day only. All-day spans collapsed the same way, to a bare <2026-07-20 Mon>.
An event whose last day is later than its start now renders as an org range,
<start>--<end>, which org parses as an active-range and shows on every day it
covers.
DTEND is the non-inclusive end of the event (RFC 5545 3.6.1), so an all-day
event's last day is DTEND-1. Getting that backwards would have been worse than
the bug: a one-day all-day event carries DTEND = start+1, so a naive range
would turn every single all-day event into a two-day one. The decrement only
applies when both ends are date-only. A date-only start with a timed end is
malformed, and treating it as all-day would put the last day before the start
and emit a backwards range. That case falls through to the same-day form, as
before.
I split out format-stamp and format-hhmm so both halves of a range and the
compact same-day form build from one place.
Same-day events are unchanged, pinned by two tests: the compact HH:MM-HH:MM
form, and a single all-day event staying a single stamp.
One unrelated bug stays open. A timed event with no DTEND renders as <date> and
drops its time, so a 09:00 meeting reads as all-day. I left it alone.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
RFC 5545 3.3.10 bounds a recurrence inclusively: when UNTIL lines up with the
recurrence, that date is the last instance. The expansion loops guarded on
calendar-sync--before-date-p, a strict comparison, so the instance landing
exactly on UNTIL was dropped. Every bounded series silently lost its last
meeting from the agenda. A series whose UNTIL equals its start date lost the
only instance it had and vanished.
I added calendar-sync--date-on-or-before-p beside --before-date-p and swapped
the three UNTIL sites: the simple-recurrence loop feeding daily, monthly and
yearly, plus both weekly checks. --before-date-p is unchanged, since a date is
still not before itself.
The two UNTIL property tests asserted the wrong invariant. They required every
occurrence to fall strictly before UNTIL, the exclusive reading the RFC
contradicts, so they pinned the defect they should have caught. The property is
now on-or-before. An upper bound alone can't catch a dropped occurrence, so I
added one asserting the series reaches its UNTIL date.
Reverting the fix failed three daily tests and one property test, and no weekly
ones. The weekly loop was fixed but unguarded, so it has its own test now.
The comparison stays date-granular, matching --date-to-time. An UNTIL carrying a
time of day earlier than the event's start will include that final instance
where the RFC would exclude it. Making it datetime-precise means reworking
--date-to-time and the timezone conversions feeding it, a much larger change
than this bug warrants.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
cj/timeformat was defvar'd inside cj/add-timestamp-to-org-entry, so the symbol
wasn't special until the command had run once. Until then a let around the call
bound it lexically and never reached the function. I moved it to top level with
a docstring. It has no other callers.
The nested defvar also poisons tests. ERT runs alphabetically, so an earlier
test that calls the command makes the symbol special retroactively. A later
special-variable-p check then passes on test ordering rather than on the code,
reading green in a full-file run and red in isolation. The new guard snapshots
special-variable-p into a defconst at load, before any test body runs.
I filled in the missing coverage: point and the following line survive the
insert, empty and unicode time strings, an empty buffer, and a read-only buffer
signalling rather than dropping the stamp. The empty-string case pins a trailing
space (current behavior, characterized rather than changed).
|
| |
|
|
|
|
|
|
| |
- A failed wf-recorder start still writes a ~0.5s stub .mkv.
- Stubs littered the recordings directory and matched *.mkv globs downstream.
- The start path now stamps the output path on the process.
- The sentinel's failed-start branch deletes that file.
- User stops and real recordings never trigger the delete.
|
| |
|
|
| |
Agents drive Signal via signal-cli and signal-mcp, so the interactive client earns no keep. I moved signal-config.el and its seven test files to archive/ per the pasture convention, dropped the require from init.el, removed the dashboard's Signal launcher (row sizes now 5 4 3 2, tests updated), and unregistered the C-; M prefix from the running daemon. The ~/code/signel fork repo is untouched. The spec record stays IMPLEMENTED with a retirement history line, and the messenger-unification draft carries a premise-shift note.
|
| |
|
|
|
|
| |
lsp-pyright's :hook lambda called require and lsp-deferred unguarded on every python-ts buffer, so a machine without pyright still got the LSP attach prompt that cj/python-setup's guard exists to prevent. The guarded branch now owns the require and the attach, and the hook is gone.
Classic python-mode now runs the same setup hooks as python-ts-mode, so treesit-auto's grammar-unavailable fallback keeps indentation, keys, and LSP. Four tests cover the guard branches and pin that every python hook entry stays a named function.
|
| |
|
|
|
|
| |
cj/slack-notify passed raw message bodies to a bare start-process. A multiline message made a giant toast, and a machine without the notify script errored inside the condition-case, so the notification silently vanished. It now routes through the same shape signel uses: whitespace collapsed and the body truncated at 120 chars, sound gated by a new cj/slack-notify-sound defcustom (silent by default), and a notifications-notify fallback when the script is absent. The fallback requires notifications.el first, which isn't autoloaded. cj/slack-test-notify exercises the same delivery path.
The shared cj/messenger-notify extraction that collapses the signel and slack copies stays with the messenger-unification task. Ten tests cover the formatter, the delivery routing, and the DM/mention predicate wiring the audit called untested.
|
| |
|
|
|
|
|
|
| |
Two picker-cache bugs from the config audit, verified against current code first.
The cache docstring promised clearing on signel-stop, but nothing cleared it, so a stale contact list survived a relink or reconnect. I advised a named clear function :after signel-stop, which makes the docstring true.
An empty listContacts result cached nil, indistinguishable from a cold cache, so a zero-contact account re-ran the picker's blocking fetch (up to the 3s timeout) on every open. The fetch now caches an empty sentinel and the picker reads through cj/signel--cached-contacts. One existing test pinned the nil behavior and now asserts the sentinel instead.
|
| |
|
|
|
|
|
|
|
|
| |
A fresh agent session now asks which runtime to run: claude, codex, or any local ollama model via codex --oss. RET keeps claude, so the common launch stays Enter-Enter. Reattaches and redisplays never ask. The picker fires only when neither a live agent buffer nor a surviving tmux session exists.
I mirrored the runtime names and launch strings from the bin/ai launcher so the two stay one mental model, and the choice list itself comes from "ai --print-runtimes" when that launcher is installed, reusing its live ollama scan and dead-server timeout. A static claude-first list stands in without it. The explicit --local-provider=ollama flag is deliberate: configuring the provider through config.toml silently does nothing.
The chosen command threads through show-or-create into the tmux launch line. On reattach, tmux new-session -A ignores it, so no reattach path changes behavior. cj/ai-term-agent-command keeps its meaning as the claude runtime's full line.
Thirteen tests cover the runtime-to-command map, the print-runtimes parsing, the launcher fallback, and the launch-command override.
|
| |
|
|
|
|
| |
The selection buffer captures MIME handles when it opens, but viewing another message kills the buffer a handle points at. Saving through such a handle died deep in mm-decode, or could write another message's bytes. The save path now signals a user-error naming the attachment when its handle's buffer is dead, and it checks before any mu4e MIME support loads, in the same spot as the existing no-handle check.
I added tests for the stale-handle error, the healthy live-handle save, and the mid-batch failure behavior (the error propagates and files already written stay).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Seven config-audit findings in mail-config, each verified against the installed mu4e 1.14 source before changing anything:
- The C-; e account nav commands now require mu4e before searching. The maps register eagerly at startup, but mu4e-search has no autoload cookie, so a nav key pressed before mu4e's first launch signaled void-function.
- With msmtp absent, both send variables now get cj/mail--send-mail-unavailable, which signals a user-error naming msmtp. The old fallback left message-send-mail-function nil (the top-level defvar pre-empts message.el's default), so the first send died with "invalid function: nil".
- I removed the unconditional org-msg-edit-mode advice on the two reply commands. org-msg-post-setup already runs on mu4e-compose-mode-hook and applies org-msg-default-alternatives itself, so the advice forced org-msg onto text-only replies and re-ran a major mode org-msg had already set up.
- I dropped the save-attachment headers action: mu4e-view-save-attachments takes no message argument and reads MIME parts from the view buffer, so it never worked from headers.
- I deleted the obsolete HTML view knobs (mu4e-view-prefer-html and both mu4e-html2text-command sets): the shr-based view has ignored them since mu4e 1.7.
- I reordered the contexts so cjennings.net comes first: with pick-first, gmail-first made gmail the silent default account for the first compose.
- I dropped mu4e-starred-folder (not a mu4e variable, never had an effect) and the obsolete mu4e-maildir alias.
New tests cover the nav-command mu4e load and the msmtp-absent fallback.
|
| |
|
|
|
|
| |
The guards from the previous commit landed without tests. I added ten: eviction of a stray live buffer to *scratch*, capture UI spared (*Org Select*, CAPTURE-*), idempotence on a window already showing *scratch*, non-popup frames untouched, nil and non-frame inputs ignored, both hook wrappers' dispatch, and hook registration.
The tests drive the real batch frame instead of mocking frame primitives: they rename it to "org-capture", exercise the guard, and revert to auto-naming. The revert must be nil, not the saved name, because Emacs refuses to set F<num>-shaped names explicitly. window-buffer-change-functions only runs during redisplay, so the module's own hook can't fire mid-test in batch.
|
| |
|
|
|
|
|
|
| |
tmux 3.7b won't emit sixel until it learns the client's cell pixel size via CSI 14/16/18 t. EAT 0.9.4's parser has no CSI t clause and drops the queries, so images never render. I added a :before advice on eat--t-handle-output that scans the raw output and answers through the terminal's own input function (eat--t-with-env binds eat--t-term). I verified it live: images render and survive window switches, scrolling, and resizing.
I guarded the advice-add so it installs only while EAT itself can't answer. Two answerers give tmux a double reply, and it forwards the second one's raw bytes into the pane as keystrokes. The guard keys on eat--t-send-window-size-report, the function an upstream clause would define.
I kept an upstream-shaped parser-clause patch locally for a PR to akib/emacs-eat.
|
| | |
|
| |
|
|
| |
org-drill-config hard-coded :load-path to ~/code/org-drill with :demand t, so on a machine without that checkout org-drill failed to load and drill broke. cj/--org-drill-source-keywords now picks the source at load time: :load-path when the checkout exists, a :vc install otherwise. The keyword is spliced through eval, since use-package needs a literal at macro-expansion.
|
| |
|
|
| |
The buffer-string calendar-sync--fetch-ics had no callers. The sync path uses the temp-file variant exclusively, so 30 lines of curl and sentinel logic that would only drift are gone. I also pulled the fetch-ics-file sentinel's finish logic into calendar-sync--fetch-sentinel-finish so its success, failure, and temp-file-cleanup branches can be tested without a live curl process. The async-worker tests stub the whole fetch and never reached them.
|
| |
|
|
| |
cj/org-contacts-find visited the contacts file before prompting, so a C-g at the prompt stranded point at the top of it. It then jumped with search-forward, which could land inside another entry's body that mentioned the name. I collect the headings with find-file-noselect first (extracted as cj/--org-contacts-collect), prompt, then jump to the selected heading's stored position. The prompt now requires a match, since a typed non-match has no position to jump to.
|
| |
|
|
| |
The seven presentation commands were bound with raw global-set-key on "C-; p ..." chains. That only works once keybindings.el has made "C-;" a live prefix. Otherwise each binding errors with "non-prefix key". I replaced them with cj/reveal-map registered under "C-; p" via cj/register-prefix-map, matching every sibling and dropping the load-order dependency.
|
| |
|
|
| |
cj/flyspell-then-abbrev ran a bare flyspell-buffer guarded by (unless flyspell-mode ...), but nothing turned flyspell-mode on, so the guard never tripped. Every C-' press re-scanned the whole buffer, which is O(buffer) per keypress in large files. I routed the scan through cj/flyspell-on-for-buffer-type instead, so the mode sticks after the first press and the buffer is scanned once.
|
| |
|
|
|
|
| |
cj/lipsum returned nil when the Markov chain was empty (for example with the training file missing), so cj/lipsum-insert ran (insert nil) and raised a cryptic wrong-type error far from the cause. It now signals a user-error naming the fix: train the chain or restore the file.
The Commentary advertised M-x cj/lipsum, but the function had no interactive spec. I added one, echoing the words interactively while still returning the string for cj/lipsum-insert and cj/lipsum-paragraphs.
|
| |
|
|
|
|
| |
edit-indirect-region was bound to "M-S-i", but pressing Meta+Shift+i produces the event M-I, not M-S-i. No keypress reached the binding, so it fell through to M-i tab-to-tab-stop. I bound it on "M-I" instead. The "was M-I" comment had it backwards: that earlier rename wasn't a no-op.
accent's C-` used accent-company, which needs the company backend. The pending Company-to-Corfu migration doesn't cover accent, so C-` would break silently once company is gone. I switched to accent-menu, which reads through the minibuffer and works regardless of the completion backend.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
C-c n p and C-c n w were bound to cj/org-roam-find-node-project and
-webclip, which no use-package :bind autoload could fulfill (they point
at org-roam, which defines neither), so both keys errored with
"autoloading failed to define function". I defined find-node-project as
a sibling of find-node-topic/recipe against the existing project.org
template, and dropped the webclip binding and label since no webclip
template or flow exists.
I repointed the v2mom/recipe/topic capture templates from
.emacs.d/org-roam-templates/ to roam-dir/templates/ so one canonical
directory feeds both the capture templates and the find-node commands.
They had drifted, and edits to one copy never reached the other. Deleted
the now-redundant .emacs.d/org-roam-templates/ files.
I removed the 28-line commented consult-org-roam block. Its proposed
C-c n l / C-c n r collide with live bindings, so it couldn't ship as
written. Git keeps the draft.
|
| |
|
|
| |
cj/title-case-region contradicted its own docstring in three ways. It lowercased "is" despite the docstring calling linking verbs major words; it never restarted capitalization after a sentence-ending period; and it had no rule to capitalize the last word. I made the code match the standard: dropped "is" from the minor-word skip list, added the period to the reset characters (a period plus a blank restarts, so "3.14" and "foo.bar" are still left alone), and always capitalize the last word by locating its start once. Updated the four characterization tests that asserted the old behavior and added tests for the last-word and period-restart rules.
|
| |
|
|
| |
cj/indent-lines-in-region-or-buffer used "p\nP", so both COUNT and USE-TABS came from the one prefix argument: no prefix gave count 1 (the docstring's "4" was wrong) with spaces, and any numeric prefix that set the count also forced tabs. Indenting several spaces was unreachable interactively. The prefix argument is now the count (defaulting to 4), and tabs-vs-spaces follows the buffer's indent-tabs-mode. cj/dedent-lines-in-region-or-buffer had the same wrong "default 4" and now defaults its count to 4 too. Added interactive-path tests, since the internals were already covered.
|
| |
|
|
| |
cj/reverse-lines and cj/number-lines split the region on newlines without accounting for a trailing one, so it became a spurious empty element. Reversing "a\nb\n" floated that empty to the top ("\nb\na"), and numbering added a phantom final numbered line. Both now strip a trailing newline before splitting and reattach it after, matching cj/--arrayify, while preserving internal blank lines. Corrected the two tests that asserted the broken output.
|
| |
|
|
|
|
|
|
|
|
| |
This module carried three editing bugs.
cj/jump-to-matching-paren, with point on a closing delimiter, ran backward-sexp from there and landed on the last inner sexp instead of the opener. It now steps past the closer first so backward-sexp spans the whole expression, and restores point when the delimiter is unmatched. Four tests that asserted the last-inner-sexp landings are corrected to the true matching opener.
cj/join-line-or-region, without a region, added a newline unconditionally after joining, which left a stray blank line when joining a line in the middle of the buffer. It now adds the newline only at end of buffer.
cj/duplicate-line-or-region duplicated a stray empty line for a region ending at beginning-of-line and split the line for a region ending mid-line. I normalized the bounds to the whole lines the region touches and insert that block once.
|
| |
|
|
|
|
| |
cj/comment-reformat printed "No region was selected" on every call, even successful ones, because the message sat outside the if. Its fill-column shrink used a raw setq and restore, so an error mid-join left fill-column permanently at -3. It now signals a user-error when there's no region and dynamically binds fill-column, which restores itself.
cj/--comment-inline-border sized the right decoration from text-length parity, leaving even-length and empty text two columns short and misaligning stacked dividers. It now fills the exact remaining width. Both fixes ship with tests, and the inline-border test asserts exact width across parities.
|
| |
|
|
| |
sortable-time-format was 12-hour with AM/PM ("%I:%M:%S %p %Z"), so "01:00:00 PM" sorted before "09:00:00 AM". I switched it to 24-hour "%H:%M:%S %Z", matching sortable-date-time, and updated the test that asserted the AM/PM output.
|
| |
|
|
| |
cj/copy-link-to-buffer-file did nothing in a non-file buffer, while every sibling copy command signals a user-error. The silent no-op gave no feedback either way. Now it signals a user-error too, and I updated the two tests and the commentary that had documented the silence as intended.
|
| |
|
|
|
|
| |
A reachability sweep from init.el found eight .el files that nothing in the config loads or references. I moved them under archive/ (off the load-path, still tracked in git) so they stay readable and restorable rather than deleted. archive/README.org records the rule (every .el outside archive/ should be actively used) and why each file was retired.
I retired show-kill-ring, duet-config, and mu4e-org-contacts-setup from modules/, and eplot, profile-dotemacs, titlecase, titlecase-data, and edit-indirect from custom/. Retiring show-kill-ring also removed the orphaned M-K -> M-S-k translation in keyboard-compat, which had left M-K a dead key. Its tests now assert seventeen translations and guard M-K's absence.
|
| |
|
|
|
|
| |
cj/view-email-in-buffer dissected the message into a handle, then signaled a user-error when it found no displayable part, before the mm-destroy-parts cleanup. The handle leaked on every image-only or attachment-only email. Wrap the body in unwind-protect so the handle is always destroyed.
While here, the eager top-level require of mm-decode only fed the mm-handle-type macro at compile time. The viewer already requires mm-decode at runtime before any mm-* call, so I moved it to eval-when-compile plus declare-function (matching the ps-print block above). Opening Emacs no longer loads mm-decode unless you view an email.
|
| |
|
|
| |
cj/theme-write-file-contents guarded on file-writable-p, which returns nil when the target's directory doesn't exist. On a fresh machine persist/ isn't there yet, so the theme write failed silently and the choice never persisted. Create the parent directory first, and still return nil if the path isn't writable.
|
| |
|
|
|
|
|
|
| |
In a single-window frame cj/kill-other-window killed the buffer being viewed: other-window no-ops, delete-window was guarded, but the kill still ran on the current buffer. Signal a user-error instead, matching the sibling cj/kill-other-window-buffer. Past the guard there's always another window, so delete-window drops its own check.
The single-window test asserted the broken behavior, so I rewrote it to expect the user-error and an untouched buffer.
Also documented the prefix-argument undead-mark in cj/kill-buffer-or-bury-alive.
|
| |
|
|
|
|
| |
emojify-display-style was computed once from env-gui-p inside the :defer'd :config block. In a daemon that block runs before any GUI frame exists, so the style latched to unicode and GUI frames never got image emoji. Recompute it per-frame from server-after-make-frame-hook, mirroring the emoji-fontset setup above.
cj/display-available-fonts called special-mode at the end, leaving the buffer read-only, so the second invocation errored on erase-buffer. Rewrite it under inhibit-read-only.
|
| |
|
|
| |
localrepo-initialize, localrepo--car-member, and the repository-id/priority defcustoms were never called: early-init.el owns adding the local archive to package-archives, with its own localrepo-location constant. The module is now just cj/update-localrepo-repository. It targets localrepo-location, so there's one archive path instead of a divergent copy. The car-member test goes with its subject. A new test pins that the mirror update uses localrepo-location.
|
| |
|
|
|
|
| |
eln-cache
cj/recompile-emacs-home selected native compilation with (boundp 'native-compile-async), but that's a function, so boundp is always nil. The command silently byte-compiled every time, even on native-comp builds. Detection now goes through cj/--native-comp-p, which uses native-comp-available-p. The native cleanup also deleted <dir>/eln, but the real cache is eln-cache/, so a stale cache survived. Both are pinned by tests: a regression on the detection helper, and the cache test now targets eln-cache.
|
| |
|
|
| |
The arrow-key decodings ran on emacs-startup-hook, but input-decode-map is terminal-local and a daemon's startup hook fires once with no tty. So every emacsclient -t frame opened later missed the decodings, and arrow keys broke in terminal frames. tty-setup-hook runs for each new tty frame, daemon and non-daemon alike. The GUI half already frame-scopes itself. A test pins the hook so a regression back to emacs-startup-hook fails.
|
| |
|
|
|
|
|
|
|
|
| |
prog-lsp.el was required by nothing. The (require 'prog-lsp) line was commented out and later deleted, so none of its config ever ran. prog-general's LSP block was the only policy in effect, which is why the build/cache file-watch ignore list added in April never applied and the "watch all files?" prompt kept firing.
Fold prog-lsp's settings into prog-general and delete the module. This adopts its quiet, performance-first policy. Doc popups, symbol highlighting, snippets, signature help, and modeline diagnostics go off. Idle-delay drops to 0.5, the eldoc provider is stripped from the global hook, and read-process-output-max rises to 1MB. The file-watch ignore list now applies: the daemon carries all thirteen build/cache patterns, six of which lsp-mode already ships by default.
Language-specific server variables and the lsp-deferred mode hooks stay in the per-language modules.
Consolidate the two prog-lsp test files into one test-prog-general-lsp.el: twelve tests covering the file-watch and eldoc helpers across Normal, Boundary, and Error, plus the load-time invariants.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Four rounds of this bug had one shape: a face nobody enumerated, sitting ahead of a mapped face in a face list and outranking it. A table header renders as (org-table-header org-table), so the mapped org-table underneath never got a say.
So this round adds a test instead of another guess. It fontifies a representative org buffer, collects every face the buffer actually uses (including the line-prefix and wrap-prefix that org-indent hangs its faces on), and fails on anything neither mapped nor deliberately excluded. It caught org-checkbox while I was writing it.
Newly dimmed: org-table-header, org-formula, org-checkbox, org-checkbox-statistics-done, org-headline-done, org-drill-visible-cloze-face.
org-indent joins org-hide and org-superstar-leading on the -hide face. All three resolve to the background colour, which is what makes folded text, leading stars and indent prefixes invisible. Flat-dimming any of them reveals what I hid.
bold, italic and underline stay unmapped on purpose. They carry no foreground even through inheritance, so they take their colour from default and dim for free.
|
| |
|
|
|
|
|
|
| |
Bullets were the last thing left lit in an unfocused org window. org-superstar puts its own face ahead of the org face beneath, so a heading star renders as (org-superstar-header-bullet org-level-1) and outranks the org-level-1 we already dim.
Three of its four faces flat-dim. The fourth, org-superstar-leading, takes the -hide face instead: its foreground is the background colour, which is exactly what keeps hidden leading stars invisible. Flat-dimming it would reveal stars I chose to hide. A test says so, so nobody completes the set later.
That closes the dimming work. The parenthesised text from the first report turned out to be org-code and org-verbatim, already covered.
|
| |
|
|
|
|
|
|
|
|
| |
flycheck-ledger registers a ledger checker, but a checker only runs where flycheck-mode is on, and flycheck-mode was hooked to sh-mode and emacs-lisp-mode only. There's no global-flycheck-mode. So an unbalanced transaction in a financial file produced no warning at all, while the ledger module's commentary advertised linting.
The hook goes in flycheck-config, not ledger-config, so that list stays the one answer to "where is flycheck turned on?".
Verified on an unbalanced fixture: flycheck now reports "Transaction does not balance" with the $10.00 remainder, on the right line.
I also accepted the whole-buffer sort the audit flagged. ledger-sort-startkey keys on the ISO date alone, and sort-subr is stable, so a save orders by date and leaves same-day transactions where they were typed. The audit note records both.
|
| |
|
|
|
|
|
|
| |
cj/test--do-focus-add-file tested containment with a bare string-prefix-p on two truenames, so tests-old/foo.el passed as being inside tests/ and joined the focus list.
The correct helper was already there. cj/test--file-in-directory-p wraps the directory in file-name-as-directory first, and the other two call sites already used it. This one didn't.
The helper even had a sibling-rejection test. It was proven correct while the call site two hundred lines away never called it, which is why the new test drives the real focus-add path with a tests-old/ directory on disk rather than testing the helper again.
|
| |
|
|
|
|
| |
link and link-visited were absent from auto-dim-other-buffers-affected-faces, so links in help, info, and customize buffers stayed lit while the rest of the window faded. They're distinct from org-link, which the earlier org pass covered.
Both carry :underline t, and the dim face sets no underline, so the relative remap drops the colour and keeps the cue. A second test pins that: if a theme ever gives auto-dim-other-buffers an :underline, dimmed links stop looking like links and the suite says so.
|
| |
|
|
|
|
|
|
| |
The linting doesn't run. flycheck-ledger loads and registers the ledger checker, but flycheck-mode is hooked to sh-mode and emacs-lisp-mode only, and there's no global-flycheck-mode. I checked a live ledger-mode buffer: checker registered, flycheck-mode nil. Unbalanced transactions and typo'd account names produce no warning, on a financial file, while the module commentary claims linting.
Three smaller findings. Every save reorders the whole file, because ledger-mode-clean-buffer calls ledger-sort-buffer over point-min to point-max. The demoted error around it lets a save proceed after a partial rewrite, with nothing to roll back. Reconcile has no confirmation and clears whole transactions.
Five characterization tests pin what exists now, including the clean-on-save default the audit questions. I fixed nothing: the guardrail choices are a separate task, and only the flycheck gap is a defect rather than a preference.
|
| |
|
|
|
|
|
|
| |
The F10 playlist docked as a right-side column when the frame was wide enough, splitting the frame three ways. That's annoying and often unexpected, so the frame's shape no longer decides where the playlist goes.
I deleted the chooser (cj/--music-playlist-side) and the right-dock width knobs rather than leaving them wired to nothing, and a test asserts they're gone. cj/preferred-dock-direction stays, since ai-term and eat still dock by frame shape.
The old side-chooser test is replaced by one that stubs cj/side-window-display and asserts what the toggle asks for, so it runs headless.
|
| |
|
|
|
|
|
|
| |
The earlier fix covered only the eleven faces the task named, so the document header (#+TITLE:, #+AUTHOR:, #+ARCHIVE: and their values), inline markup, drawers, planning lines, tables, and the fold indicator all stayed lit in unfocused windows.
I enumerated the faces a fontified org buffer actually uses, rather than adding only the ones I could see were wrong. Fifteen were missing.
org-todo and org-priority stay out of the flat-dim set. They're keyword class, and dimming them would erase the status colour the org-faces-*-dim variants preserve. Two tests pin that exclusion, and a third pins org-hide to the -hide face so folded text stays hidden.
|
| |
|
|
|
|
|
|
| |
org-level-1..8, org-link, and org-tag were missing from auto-dim-other-buffers-affected-faces, so they stayed lit while the rest of an unfocused window faded.
I flat-dimmed them rather than giving them -dim variants. The active theme gives all eight heading levels one foreground and no height or weight, so no level-by-colour signal is lost. The fork remaps relatively, so org-link keeps its underline and the stars and org-indent keep conveying depth. That premise is theme-dependent, and the comment says so.
A second test pins the keyword and priority faces to their -dim variants, so a later change can't quietly flat-dim those too.
|
| |
|
|
|
|
| |
The two radio search commands were reachable only as n/t inside the playlist buffer, and R jumped straight into the manual name+URL entry. r is now a radio prefix with the same letters the playlist's Radio row uses: n searches by name, t by tag, m is the manual entry.
The rest of the menu's uppercase keys moved to lowercase homes: v shows the playlist (was M), u shuffles (was Z), and repeat-playlist moved from r to l to free the radio prefix. In the playlist buffer, save moved from w to v.
|
| |
|
|
|
|
|
|
| |
The radio-browser lookup and the manual station creator no longer write .m3u files at pick time. Picks become url tracks in the queue, carrying the station name, uuid, and favicon as track properties, and play immediately. The display and cover-art layers read the properties first and fall back to the on-disk metadata, so existing station files keep working.
Saving is the normal playlist save, now on w. The radio feature's S=stop rebind had silently shadowed the old S=save binding. An all-stream queue saves into the MPD playlist dir, and the station name pre-fills the prompt with no -Radio suffix. A custom emitter writes the station metadata back out as .m3u comment lines, since the stock EMMS writer emits bare URLs and would lose names and cover art on reload.
I removed the write-at-pick machinery (station-m3u, write-stations, disambiguate-name, the -Radio filename suffix) and the orphaned safe-filename helper. An empty name at the save prompt now signals an error instead of writing a hidden .m3u.
|