From 7ce43f29a754d68db5a3c8683f01e7f9698a32e8 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 25 May 2026 18:29:31 -0500 Subject: fix(font-config): theme-aware browser labels and daemon-safe emoji fontset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two font-config robustness fixes. The font-browser (cj/display-available-fonts) hardcoded a "Light Blue" foreground for each family label, which goes nearly unreadable on a light theme. I switched it to font-lock-keyword-face so the label follows the theme's contrast, keeping it bold. The emoji-fontset cond ran once at module load behind (env-gui-p). In daemon mode there's no GUI frame at load, so env-gui-p is nil and the fontset never gets set — a later emacsclient -c GUI frame then has no emoji font. I wrapped it in cj/setup-emoji-fontset (GUI-guarded, idempotent) and, mirroring how the fontaine preset is already applied, run it from server-after-make-frame-hook in daemon mode and directly otherwise. The daemon TTY-then-GUI path can't be exercised in batch, so I left a manual-test entry for it. --- modules/font-config.el | 35 +++++++++++++++++++++++------------ tests/test-font-config.el | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/modules/font-config.el b/modules/font-config.el index d4e2190d..39d21364 100644 --- a/modules/font-config.el +++ b/modules/font-config.el @@ -222,17 +222,28 @@ If FRAME is nil, uses the selected frame." ;; ----------------------------- Emoji Fonts Per OS ---------------------------- ;; Set emoji fonts in priority order (first found wins) -(when (env-gui-p) - (cond - ;; Prefer Noto Color Emoji (Linux) - ((member "Noto Color Emoji" (font-family-list)) - (set-fontset-font t 'symbol (font-spec :family "Noto Color Emoji") nil 'prepend)) - ;; Then Apple Color Emoji (macOS) - ((member "Apple Color Emoji" (font-family-list)) - (set-fontset-font t 'symbol (font-spec :family "Apple Color Emoji") nil 'prepend)) - ;; Finally Segoe UI Emoji (Windows) - ((member "Segoe UI Emoji" (font-family-list)) - (set-fontset-font t 'symbol (font-spec :family "Segoe UI Emoji") nil 'prepend)))) +(defun cj/setup-emoji-fontset (&optional _frame) + "Set emoji fonts in priority order (first found wins). +No-op unless a GUI frame is present. Safe to run per-frame: setting +the fontset repeatedly is harmless, so it can be called from +`server-after-make-frame-hook' in daemon mode." + (when (env-gui-p) + (cond + ;; Prefer Noto Color Emoji (Linux) + ((member "Noto Color Emoji" (font-family-list)) + (set-fontset-font t 'symbol (font-spec :family "Noto Color Emoji") nil 'prepend)) + ;; Then Apple Color Emoji (macOS) + ((member "Apple Color Emoji" (font-family-list)) + (set-fontset-font t 'symbol (font-spec :family "Apple Color Emoji") nil 'prepend)) + ;; Finally Segoe UI Emoji (Windows) + ((member "Segoe UI Emoji" (font-family-list)) + (set-fontset-font t 'symbol (font-spec :family "Segoe UI Emoji") nil 'prepend))))) + +;; In daemon mode `env-gui-p' is nil at load time (no GUI frame yet), so run +;; the setup per-frame as GUI frames are created. Otherwise run it now. +(if (daemonp) + (add-hook 'server-after-make-frame-hook #'cj/setup-emoji-fontset) + (cj/setup-emoji-fontset)) ;; ---------------------------------- Emojify ---------------------------------- ;; converts emoji identifiers into emojis; allows for easy emoji entry. @@ -272,7 +283,7 @@ If FRAME is nil, uses the selected frame." (with-current-buffer "*Available Fonts*" (erase-buffer) (dolist (font-family font-list) - (insert (propertize (concat font-family) 'face `((:foreground "Light Blue" :weight bold)))) + (insert (propertize (concat font-family) 'face '(font-lock-keyword-face (:weight bold)))) (insert (concat "\n"(propertize "Regular: "))) (insert (propertize (concat "The quick brown fox jumps over the lazy dog I 1 l ! : ; . , 0 O o [ { ( ) } ] ?") 'face `((:family, font-family)))) diff --git a/tests/test-font-config.el b/tests/test-font-config.el index c4a649c2..8fada25e 100644 --- a/tests/test-font-config.el +++ b/tests/test-font-config.el @@ -70,5 +70,28 @@ (should (= calls 1)) (should (memq (selected-frame) cj/fontaine-configured-frames))))) +;;; cj/setup-emoji-fontset + +(ert-deftest test-font-config-setup-emoji-fontset-noop-without-gui () + "Boundary: without a GUI the emoji setup does nothing and does not error." + (skip-unless test-font-config--available) + (require 'font-config) + (let ((called nil)) + (cl-letf (((symbol-function 'env-gui-p) (lambda (&rest _) nil)) + ((symbol-function 'set-fontset-font) + (lambda (&rest _) (setq called t)))) + (cj/setup-emoji-fontset) + (should-not called)))) + +(ert-deftest test-font-config-setup-emoji-fontset-runs-on-gui () + "Normal: on a GUI frame the emoji setup runs without error." + (skip-unless test-font-config--available) + (require 'font-config) + (cl-letf (((symbol-function 'env-gui-p) (lambda (&rest _) t)) + ((symbol-function 'font-family-list) + (lambda (&rest _) '("Noto Color Emoji"))) + ((symbol-function 'set-fontset-font) (lambda (&rest _) t))) + (should (progn (cj/setup-emoji-fontset) t)))) + (provide 'test-font-config) ;;; test-font-config.el ends here -- cgit v1.2.3