aboutsummaryrefslogtreecommitdiff
path: root/modules/nerd-icons-config.el
blob: d3d55b8642553a6e91b8fc64f1a7401f59ba3f25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
;;; nerd-icons-config.el --- Nerd-icons setup, integrations, and tinting -*- lexical-binding: t; -*-
;; author: Craig Jennings <c@cjennings.net>

;;; Commentary:
;;
;; Layer: 2 (Core UX).
;; Category: C/P.
;; Load shape: eager.
;; Eager reason: provides the nerd-icons fonts that dashboard, modeline, and
;;   completion render in the first frame.
;; Top-level side effects: package configuration via use-package.
;; Runtime requires: none.
;; Direct test load: yes.
;;
;; Single home for nerd-icons:
;;   - the package itself
;;   - completion integration (`nerd-icons-completion')
;;   - ibuffer integration (`nerd-icons-ibuffer')
;;   - bulk color tinting of every `nerd-icons-*' color face
;;   - dir-icon color advice (so directory glyphs carry a color face like
;;     file glyphs do, instead of falling through to the buffer default
;;     face)
;;
;; Per-feature USE of nerd-icons stays in the feature module that consumes
;; it: `dashboard-icon-type', `dirvish-attributes', and the keyboard-compat
;; terminal-frame icon-blanking advice are not centralized here.

;;; Code:

;; ----------------------------- Customization ---------------------------------

(defcustom cj/nerd-icons-tint-color "darkgoldenrod"
  "Single foreground color applied to every `nerd-icons-*' color face.
Set via Customize or by `setq' before this module loads, then call
`cj/nerd-icons-apply-tint' to re-apply on demand."
  :type 'string
  :group 'cj)

(defconst cj/--nerd-icons-color-faces
  '(nerd-icons-red       nerd-icons-lred       nerd-icons-dred       nerd-icons-red-alt
    nerd-icons-green     nerd-icons-lgreen     nerd-icons-dgreen
    nerd-icons-yellow    nerd-icons-lyellow    nerd-icons-dyellow
    nerd-icons-orange    nerd-icons-lorange    nerd-icons-dorange
    nerd-icons-blue      nerd-icons-blue-alt   nerd-icons-lblue      nerd-icons-dblue
    nerd-icons-cyan      nerd-icons-cyan-alt   nerd-icons-lcyan      nerd-icons-dcyan
    nerd-icons-purple    nerd-icons-purple-alt nerd-icons-lpurple    nerd-icons-dpurple
    nerd-icons-pink      nerd-icons-lpink      nerd-icons-dpink
    nerd-icons-maroon    nerd-icons-lmaroon    nerd-icons-dmaroon
    nerd-icons-silver    nerd-icons-lsilver    nerd-icons-dsilver)
  "Every color face nerd-icons attaches to glyphs via `:inherit'.")

;; ------------------------------- Helpers -------------------------------------

(defun cj/nerd-icons-apply-tint (&optional color)
  "Set every face in `cj/--nerd-icons-color-faces' to foreground COLOR.
COLOR defaults to `cj/nerd-icons-tint-color'. Faces that are not yet
defined (nerd-icons not loaded) are silently skipped."
  (interactive)
  (let ((c (or color cj/nerd-icons-tint-color)))
    (dolist (f cj/--nerd-icons-color-faces)
      (when (facep f)
        (set-face-foreground f c)))))

(defun cj/--nerd-icons-color-dir (icon)
  "Layer `nerd-icons-yellow' onto ICON's face stack and return ICON.
ICON is the propertized string returned by `nerd-icons-icon-for-dir'.
Without this, directory icons render in the buffer default face — so a
buffer-local face-remap of `default' catches them unintentionally.

Idempotent: nerd-icons memoizes its return strings, and this advice modifies
in place, so a naive `add-face-text-property' would stack the face symbol on
every call. The `memq' check skips when the face is already present."
  (when (and (stringp icon) (> (length icon) 0))
    (let ((faces (ensure-list (get-text-property 0 'face icon))))
      (unless (memq 'nerd-icons-yellow faces)
        (add-face-text-property 0 (length icon) 'nerd-icons-yellow nil icon))))
  icon)

;; ------------------------------- Packages ------------------------------------

;; `:demand t' is required: `dashboard-config.el' calls
;; `nerd-icons-faicon' / `nerd-icons-mdicon' / `nerd-icons-devicon' at
;; load time to build `dashboard-navigator-buttons', so nerd-icons must
;; be loaded eagerly before dashboard-config requires.  The earlier
;; deferral attempt (commit d618bb46) broke startup with a
;; `void-function nerd-icons-faicon' error.
(use-package nerd-icons
  :demand t
  :config
  (advice-add 'nerd-icons-icon-for-dir :filter-return #'cj/--nerd-icons-color-dir)
  (cj/nerd-icons-apply-tint))

;; Safety net: if this module is re-evaluated in a running Emacs where
;; nerd-icons is already loaded, `:config' above won't fire again --
;; ensure the advice and tint still apply.
(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)
  :hook (marginalia-mode . nerd-icons-completion-marginalia-setup)
  :config
  (nerd-icons-completion-mode))

(use-package nerd-icons-ibuffer
  :after nerd-icons
  :hook (ibuffer-mode . nerd-icons-ibuffer-mode)
  :custom
  (nerd-icons-ibuffer-icon t)
  (nerd-icons-ibuffer-color-icon t)
  (nerd-icons-ibuffer-human-readable-size t))

(provide 'nerd-icons-config)
;;; nerd-icons-config.el ends here