aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-14 15:43:36 -0500
committerCraig Jennings <c@cjennings.net>2026-06-14 15:43:36 -0500
commit92c062b8b4cc70b09d5487d1cc29287ad52babdf (patch)
tree418d0b261f85c7183ae925cc171ae13ba1322282
parent808607872702075e638e5813f3c2958c100cdb6c (diff)
downloaddotemacs-92c062b8b4cc70b09d5487d1cc29287ad52babdf.tar.gz
dotemacs-92c062b8b4cc70b09d5487d1cc29287ad52babdf.zip
fix(erc): one mention notification, real server list, runtime require
Three audit defects. erc-modules carried the built-in notifications module while :config also added cj/erc-notify-on-mention to the same erc-text-matched-hook, so every mention popped two desktop notifications. Dropped notifications from erc-modules and kept the custom one. cj/erc-connected-servers compared a buffer's erc-server-process to itself inside with-current-buffer (always true), so it returned every ERC buffer; it now filters on erc-server-buffer-p and erc-server-process-alive. And user-constants moved from an eval-when-compile-only require to a runtime require, since user-whole-name is read at load time for erc-user-full-name.
-rw-r--r--modules/erc-config.el9
-rw-r--r--tests/test-erc-config-connected-servers.el48
-rw-r--r--todo.org18
3 files changed, 70 insertions, 5 deletions
diff --git a/modules/erc-config.el b/modules/erc-config.el
index 22ba7f53d..067b1e577 100644
--- a/modules/erc-config.el
+++ b/modules/erc-config.el
@@ -28,8 +28,10 @@
;; Load cl-lib at compile time and runtime (lightweight, already loaded in most configs)
(require 'cl-lib)
(require 'keybindings) ;; provides cj/custom-keymap
-(eval-when-compile (require 'erc)
- (require 'user-constants))
+(eval-when-compile (require 'erc))
+;; user-constants is required at runtime, not just compile time: `user-whole-name'
+;; is read at load time below (erc-user-full-name), so a standalone .elc needs it.
+(require 'user-constants)
;; ------------------------------------ ERC ------------------------------------
;; Server definitions and connection settings
@@ -97,7 +99,7 @@ Change this value to use a different nickname.")
(let ((server-buffers '()))
(dolist (buf (erc-buffer-list))
(with-current-buffer buf
- (when (eq (buffer-local-value 'erc-server-process buf) erc-server-process)
+ (when (and (erc-server-buffer-p) (erc-server-process-alive))
(unless (member (buffer-name) server-buffers)
(push (buffer-name) server-buffers)))))
@@ -222,7 +224,6 @@ Auto-adds # prefix if missing. Offers completion from configured channels."
match
move-to-prompt
noncommands
- notifications
readonly
services
stamp
diff --git a/tests/test-erc-config-connected-servers.el b/tests/test-erc-config-connected-servers.el
new file mode 100644
index 000000000..7d4540d68
--- /dev/null
+++ b/tests/test-erc-config-connected-servers.el
@@ -0,0 +1,48 @@
+;;; test-erc-config-connected-servers.el --- cj/erc-connected-servers -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; cj/erc-connected-servers must return only ERC *server* buffers with a live
+;; process. The original test compared a buffer's own erc-server-process to the
+;; same buffer-local value inside `with-current-buffer', which is always true, so
+;; it returned every ERC buffer (channels, queries, dead connections). These
+;; tests stub `erc-buffer-list' and the two ERC predicates so the classification
+;; is exercised without a real IRC connection.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+
+(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))
+(require 'erc-config)
+
+(ert-deftest test-erc-connected-servers-keeps-only-live-server-buffers ()
+ "Normal: only buffers that are ERC server buffers with a live process are
+returned; a channel buffer and a dead-connection server buffer are excluded."
+ (let ((b-server (generate-new-buffer " *erc-server*"))
+ (b-channel (generate-new-buffer " *erc-#chan*"))
+ (b-dead (generate-new-buffer " *erc-dead*")))
+ (unwind-protect
+ (cl-letf (((symbol-function 'erc-buffer-list)
+ (lambda (&rest _) (list b-server b-channel b-dead)))
+ ((symbol-function 'erc-server-buffer-p)
+ (lambda (&rest _) (memq (current-buffer) (list b-server b-dead))))
+ ((symbol-function 'erc-server-process-alive)
+ (lambda (&rest _) (eq (current-buffer) b-server))))
+ (should (equal (cj/erc-connected-servers)
+ (list (buffer-name b-server)))))
+ (mapc #'kill-buffer (list b-server b-channel b-dead)))))
+
+(ert-deftest test-erc-connected-servers-empty-when-none-alive ()
+ "Boundary: no live server buffers yields an empty list."
+ (let ((b-channel (generate-new-buffer " *erc-#chan*")))
+ (unwind-protect
+ (cl-letf (((symbol-function 'erc-buffer-list)
+ (lambda (&rest _) (list b-channel)))
+ ((symbol-function 'erc-server-buffer-p) (lambda (&rest _) nil))
+ ((symbol-function 'erc-server-process-alive) (lambda (&rest _) nil)))
+ (should (null (cj/erc-connected-servers))))
+ (kill-buffer b-channel))))
+
+(provide 'test-erc-config-connected-servers)
+;;; test-erc-config-connected-servers.el ends here
diff --git a/todo.org b/todo.org
index dd53ce811..12a62350e 100644
--- a/todo.org
+++ b/todo.org
@@ -195,6 +195,14 @@ Spec draft: [[file:docs/theme-studio-palette-generator-spec.org][theme-studio-pa
Build a constraint-first palette generator for Theme Studio: start from bg/fg, generate editable palette columns in OKLCH, preview candidate columns before applying them, and apply proposals by append/replace/regenerate modes while preserving stable column ids and existing assignments where possible. V1 is palette-only, not automatic face assignment; generator output becomes normal editable columns after apply.
+** TODO [#B] theme-studio semantic theme architecture :feature:theme-studio:spec:
+:PROPERTIES:
+:LAST_REVIEWED: 2026-06-14
+:END:
+Spec draft: [[file:docs/theme-studio-semantic-theme-architecture-spec.org][theme-studio-semantic-theme-architecture-spec.org]].
+
+Design a Modus-inspired layered Theme Studio output path: palette data, semantic role mappings, face templates, and a generated theme wrapper. Keep the current flat JSON-to-theme converter as the compatibility/default path while proving a layered, self-contained generated theme. Include advisory semantic rules as a possible validation layer, not v1 enforcement.
+
*** TODO [#C] theme-studio palette generator source modes for base-only vs ground-aware palettes :feature:
:PROPERTIES:
:LAST_REVIEWED: 2026-06-14
@@ -970,11 +978,13 @@ From the 2026-06 config audit, =modules/calendar-sync.el=:
- =:1284= — curl runs without =--fail=: an HTTP 404/500 error page exits 0 and the HTML proceeds into conversion.
- =:1229-1233= — =--parse-ics= returns nil for both garbage and a valid calendar with zero in-window events, so healthy near-empty calendars report "parse failed" in =calendar-sync-status=. Distinguish the cases.
-** TODO [#B] ERC: double mention notifications + tautological server list :bug:quick:solo:
+** DONE [#B] ERC: double mention notifications + tautological server list :bug:quick:solo:
+CLOSED: [2026-06-14 Sun]
From the 2026-06 config audit, =modules/erc-config.el=:
- =:281= — =erc-modules= includes the built-in =notifications= module AND :config adds =cj/erc-notify-on-mention= to the same hook — every mention fires two desktop notifications. Pick one path (keep the custom one, slated for messenger unification).
- =:100= — =cj/erc-connected-servers=: inside =with-current-buffer=, the free =erc-server-process= is the buffer's own local value, so the eq test is tautologically true — returns ALL ERC buffers (channels, dead connections). Use =erc-server-buffer-p= + =erc-server-process-alive=.
- =:238= — =user-whole-name= read at load but =user-constants= only required at compile time (same trap as auth-config/keyboard-macros).
+Fixed 2026-06-14: removed =notifications= from =erc-modules= (kept the custom =cj/erc-notify-on-mention=, so one notification per mention); rewrote =cj/erc-connected-servers= to filter on =(erc-server-buffer-p)= + =(erc-server-process-alive)= instead of the tautological self-eq; moved =user-constants= to a runtime require. New test-erc-config-connected-servers.el (live-server-only + empty cases) 2 green; module byte-compiles. erc-config not reloaded into the daemon (live IRC session) — takes effect on restart. VERIFY for the one-notification + real-server-list behavior.
** TODO [#B] slack-config lifecycle gaps :bug:quick:solo:
From the 2026-06 config audit, =modules/slack-config.el=:
@@ -4441,6 +4451,12 @@ From the 2026-06-11 messenger-unification brainstorm. Google Voice has no offici
** TODO Manual testing and validation
Exercised once the phases above land.
+*** VERIFY ERC fires one mention notification and lists real servers
+What we're verifying: a mention pops a single desktop notification (not two), and cj/erc-connected-servers lists only live server connections. Fixed in modules/erc-config.el; takes effect after an Emacs restart (not reloaded into the live IRC session).
+- Restart Emacs and reconnect ERC
+- Have someone mention your nick in a channel (or trigger erc-text-matched-hook)
+- Run M-x cj/erc-connected-servers with one server connected and a few channels open
+Expected: exactly one desktop notification per mention; cj/erc-connected-servers reports just the connected server(s), not every channel/query buffer.
*** VERIFY modeline still shows the git branch and state
What we're verifying: the VC-cache simplification didn't change what the modeline shows on a normal repo. Fixed in modules/modeline-config.el (live in the daemon after reload).
- Open a file inside a git repo