aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-16 02:56:25 -0500
committerCraig Jennings <c@cjennings.net>2026-05-16 02:56:25 -0500
commitd618bb4620d5d651027e772b8ccc490e1bab6d80 (patch)
treebd0b6d0e2fcde37a0ca27f038a19bac8b39f3578 /modules
parenta9a4d8c7148c115a242a7b35d16dd536f9c0c700 (diff)
downloaddotemacs-d618bb4620d5d651027e772b8ccc490e1bab6d80.tar.gz
dotemacs-d618bb4620d5d651027e772b8ccc490e1bab6d80.zip
refactor(ui): four UI/navigation hygiene fixes from module-by-module re-review
- popper-config.el: move `(popper-mode +1)` and `(popper-echo-mode +1)` from the use-package `:init` block into `:config`. `:disabled t' on use-package skips `:config' but still runs `:init', so the previous shape enabled popper-mode on every load, including batch / test runs, despite the disabled marker. - modeline-config.el: make `cj/modeline-vc-fetch' fall back when the internal `vc-git--symbolic-ref' is missing. `require' uses `nil 'noerror', the call sits inside an `fboundp' guard, and `ignore-errors' wraps the call itself so an Emacs version that renames or removes the accessor leaves `branch' at `vc-working-revision''s output instead of crashing the modeline. - ui-config.el: guard the cursor-color `post-command-hook' behind `(display-graphic-p)' both at install time and inside the function body. Batch / TTY runs short-circuit cleanly with no per-command overhead. A `server-after-make-frame-hook' catches the daemon case where the first GUI frame is created after ui-config loads and installs the hook lazily. Updates test-ui-config--buffer-cursor-state and test-ui-cursor-color-integration to stub `display-graphic-p' so the work body still runs under batch. - nerd-icons-config.el: drop `:demand t' (`:defer t' now), keeping the `:config' advice install as the natural lazy-on-load path. Add a `with-eval-after-load 'nerd-icons' block as a safety net for the already-loaded case on re-eval; the block uses `advice-member-p' so the advice never stacks.
Diffstat (limited to 'modules')
-rw-r--r--modules/modeline-config.el13
-rw-r--r--modules/nerd-icons-config.el12
-rw-r--r--modules/popper-config.el4
-rw-r--r--modules/ui-config.el41
4 files changed, 52 insertions, 18 deletions
diff --git a/modules/modeline-config.el b/modules/modeline-config.el
index 771d960f..61ab0f9d 100644
--- a/modules/modeline-config.el
+++ b/modules/modeline-config.el
@@ -141,15 +141,20 @@ Uses built-in cached values for performance.")
(defun cj/modeline-vc-fetch (file)
"Fetch modeline VC data for FILE.
-Return a plist with `:branch' and `:state', or nil when FILE has no VC data."
+Return a plist with `:branch' and `:state', or nil when FILE has no VC data.
+Uses `vc-git--symbolic-ref' for branch names when available (it returns the
+symbolic ref like \"main\" instead of a SHA when HEAD is on a branch), but
+falls back to `vc-working-revision' if the internal accessor is missing --
+the symbol is internal and can be renamed or removed between Emacs versions."
(unless (and (file-remote-p file) (not cj/modeline-vc-show-remote))
(when-let* ((backend (vc-backend file))
(branch (vc-working-revision file backend)))
(when (eq backend 'Git)
(unless (fboundp 'vc-git--symbolic-ref)
- (require 'vc-git))
- (when-let* ((symbolic (vc-git--symbolic-ref file)))
- (setq branch symbolic)))
+ (require 'vc-git nil 'noerror))
+ (when (fboundp 'vc-git--symbolic-ref)
+ (when-let* ((symbolic (ignore-errors (vc-git--symbolic-ref file))))
+ (setq branch symbolic))))
(list :branch branch
:state (vc-state file backend)))))
diff --git a/modules/nerd-icons-config.el b/modules/nerd-icons-config.el
index 4a8ce194..52a4627d 100644
--- a/modules/nerd-icons-config.el
+++ b/modules/nerd-icons-config.el
@@ -70,11 +70,21 @@ every call. The `memq' check skips when the face is already present."
;; ------------------------------- Packages ------------------------------------
(use-package nerd-icons
- :demand t
+ :defer t
:config
(advice-add 'nerd-icons-icon-for-dir :filter-return #'cj/--nerd-icons-color-dir)
(cj/nerd-icons-apply-tint))
+;; If nerd-icons is already loaded (e.g. when this module is re-evaluated
+;; after a session in which a feature module already required it), the
+;; `:config' block above won't fire again -- fall through to install the
+;; advice and tint immediately.
+(with-eval-after-load 'nerd-icons
+ (unless (advice-member-p #'cj/--nerd-icons-color-dir 'nerd-icons-icon-for-dir)
+ (advice-add 'nerd-icons-icon-for-dir
+ :filter-return #'cj/--nerd-icons-color-dir))
+ (cj/nerd-icons-apply-tint))
+
(use-package nerd-icons-completion
:demand t
:after (nerd-icons marginalia)
diff --git a/modules/popper-config.el b/modules/popper-config.el
index 359e789c..35780eb2 100644
--- a/modules/popper-config.el
+++ b/modules/popper-config.el
@@ -37,6 +37,10 @@
(side . bottom)
(slot . 0)
(window-height . 0.5))) ; Half the frame height
+ ;; Mode activation moves to :config so `:disabled t' actually
+ ;; disables it (`:init' runs even when `:disabled t', `:config'
+ ;; does not).
+ :config
(popper-mode +1)
(popper-echo-mode +1))
diff --git a/modules/ui-config.el b/modules/ui-config.el
index 5d3a6643..39b86182 100644
--- a/modules/ui-config.el
+++ b/modules/ui-config.el
@@ -120,21 +120,36 @@ through to `read-only' and keeps the orange cursor."
(defun cj/set-cursor-color-according-to-mode ()
"Change cursor color according to buffer state (modified, read-only, overwrite).
-Only updates for real user buffers, not internal/temporary buffers."
- ;; Only update cursor for real buffers (not internal ones like *temp*, *Echo Area*, etc.)
- (unless (string-prefix-p " " (buffer-name)) ; Internal buffers start with space
- (let ((color (alist-get (cj/--buffer-cursor-state) cj/buffer-status-colors)))
- ;; Only skip if BOTH color AND buffer are the same (optimization)
- ;; This allows color to update when buffer state changes
- (unless (and (string= color cj/-cursor-last-color)
- (string= (buffer-name) cj/-cursor-last-buffer))
- (set-cursor-color color)
- (setq cj/-cursor-last-color color
- cj/-cursor-last-buffer (buffer-name))))))
+Only updates for real user buffers, not internal/temporary buffers.
+A no-op on non-graphical frames -- TTY/batch sessions have no cursor color
+to set."
+ (when (display-graphic-p)
+ ;; Only update cursor for real buffers (not internal ones like *temp*, *Echo Area*, etc.)
+ (unless (string-prefix-p " " (buffer-name)) ; Internal buffers start with space
+ (let ((color (alist-get (cj/--buffer-cursor-state) cj/buffer-status-colors)))
+ ;; Only skip if BOTH color AND buffer are the same (optimization)
+ ;; This allows color to update when buffer state changes
+ (unless (and (string= color cj/-cursor-last-color)
+ (string= (buffer-name) cj/-cursor-last-buffer))
+ (set-cursor-color color)
+ (setq cj/-cursor-last-color color
+ cj/-cursor-last-buffer (buffer-name)))))))
;; Use post-command-hook to update cursor color after every command
-;; This ensures cursor color always matches the current buffer's state
-(add-hook 'post-command-hook #'cj/set-cursor-color-according-to-mode)
+;; This ensures cursor color always matches the current buffer's state.
+;; The hook only registers under a graphical session so batch / TTY runs
+;; don't pay per-command overhead for a no-op.
+(when (display-graphic-p)
+ (add-hook 'post-command-hook #'cj/set-cursor-color-according-to-mode))
+;; Daemon mode: the first frame may be created after this module loads.
+;; Re-attempt the hook install once a GUI frame appears.
+(add-hook 'server-after-make-frame-hook
+ (lambda ()
+ (when (and (display-graphic-p)
+ (not (memq #'cj/set-cursor-color-according-to-mode
+ post-command-hook)))
+ (add-hook 'post-command-hook
+ #'cj/set-cursor-color-according-to-mode))))
;; Don’t show a cursor in non-selected windows:
(setq cursor-in-non-selected-windows nil)