From 7ccc3f5c0d688914eff0f8501f85d3f40ab8601d Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 14 Jun 2026 17:23:37 -0500 Subject: refactor(ui): color the cursor and modeline from theme faces, in sync The cursor color and the modeline buffer-name indicator both hard-coded hex colors through cj/buffer-status-colors. Replaced that constant with cj/buffer-status-faces, mapping each buffer state to a theme face: read-only to error, overwrite and modified to warning, unmodified to success. A shared classifier (cj/buffer-status-state) and resolver (cj/buffer-status-color) in user-constants now drive both consumers, so the cursor and the modeline resolve their color from the active theme at use time and stay in sync, including the ghostel-terminal case the cursor already special-cased. Tests cover the map, the classifier, the resolver, and both integration paths. --- modules/user-constants.el | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'modules/user-constants.el') diff --git a/modules/user-constants.el b/modules/user-constants.el index 2e64b355e..1ee8ecda3 100644 --- a/modules/user-constants.el +++ b/modules/user-constants.el @@ -55,13 +55,44 @@ mail, chime, etc." ;; ---------------------------- Buffer Status Colors --------------------------- -(defconst cj/buffer-status-colors - '((read-only . "#f06a3f") ; red – buffer is read-only - (overwrite . "#c48702") ; gold – overwrite mode - (modified . "#64aa0f") ; green – modified & writeable - (unmodified . "#ffffff")) ; white – unmodified & writeable - "Alist mapping buffer states to their colors. -Used by cursor color, modeline, and other UI elements.") +(defconst cj/buffer-status-faces + '((read-only . error) ; can't edit + (overwrite . warning) ; overwrite mode + (modified . warning) ; writeable, with unsaved changes + (unmodified . success)) ; clean and writeable + "Alist mapping a buffer state to the theme face whose foreground colors it. +Shared by the cursor color (ui-config.el) and the modeline buffer-status +indicator (modeline-config.el) so the two stay in sync and follow the active +theme, rather than hard-coding hex colors.") + +(defun cj/buffer-status-state () + "Return the buffer-state symbol for the current buffer. +One of `read-only', `overwrite', `modified', or `unmodified' -- the keys of +`cj/buffer-status-faces'. + +A live ghostel terminal (in `ghostel-mode' and an input mode that forwards keys +-- semi-char / char / line) reports `unmodified' even though the buffer is +read-only: keystrokes go to the terminal process, so from the user's side it is +writeable and the read-only state would be misleading. ghostel's `copy' and +`emacs' input modes are the exception -- there the buffer really is a read-only +Emacs buffer the user navigates, so it falls through to `read-only'." + (cond + ((and (eq major-mode 'ghostel-mode) + (not (memq (bound-and-true-p ghostel--input-mode) '(copy emacs)))) + 'unmodified) + (buffer-read-only 'read-only) + (overwrite-mode 'overwrite) + ((buffer-modified-p) 'modified) + (t 'unmodified))) + +(defun cj/buffer-status-color (state) + "Return the foreground color of the theme face mapped to buffer STATE. +Resolves STATE through `cj/buffer-status-faces' against the active theme. Nil +when the state is unknown or its face has no concrete foreground (face-attribute +returns the symbol `unspecified' there), so callers can skip cleanly." + (when-let* ((face (alist-get state cj/buffer-status-faces)) + (fg (face-attribute face :foreground nil t))) + (and (stringp fg) fg))) ;; --------------------------- Media File Extensions --------------------------- -- cgit v1.2.3