1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 (defconst list-faces-sample-text
6 "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"
7 "Text string to display as the sample text for `list-faces-display'.")
10 ;; The name list-faces would be more consistent, but let's avoid a
11 ;; conflict with Lucid, which uses that name differently.
13 (defvar help-xref-stack
)
14 (defun list-faces-display (&optional regexp
)
15 "List all faces, using the same sample text in each.
16 The sample text is a string that comes from the variable
17 `list-faces-sample-text'.
19 If REGEXP is non-nil, list only those faces with names matching
20 this regular expression. When called interactively with a prefix
21 arg, prompt for a regular expression."
22 (interactive (list (and current-prefix-arg
23 (read-regexp "List faces matching regexp"))))
24 (let ((all-faces (zerop (length regexp
)))
25 (frame (selected-frame))
28 disp-frame window face-name
)
29 ;; We filter and take the max length in one pass
33 (let ((s (symbol-name f
)))
34 (when (or all-faces
(string-match-p regexp s
))
35 (setq max-length
(max (length s
) max-length
))
37 (sort (face-list) #'string-lessp
))))
39 (error "No faces matching \"%s\"" regexp
))
40 (setq max-length
(1+ max-length
)
41 line-format
(format "%%-%ds" max-length
))
42 (with-help-window "*Faces*"
43 (with-current-buffer standard-output
44 (setq truncate-lines t
)
46 (substitute-command-keys
48 "\\<help-mode-map>Use "
49 (if (display-mouse-p) "\\[help-follow-mouse] or ")
50 "\\[help-follow] on a face name to customize it\n"
51 "or on its sample text for a description of the face.\n\n")))
52 (setq help-xref-stack nil
)
54 (setq face-name
(symbol-name face
))
55 (insert (format line-format face-name
))
56 ;; Hyperlink to a customization buffer for the face. Using
57 ;; the help xref mechanism may not be the best way.
60 (search-backward face-name
)
61 (setq help-xref-stack-item
`(list-faces-display ,regexp
))
62 (help-xref-button 0 'help-customize-face face
)))
64 (line-beg (line-beginning-position)))
65 (insert list-faces-sample-text
)
66 ;; Hyperlink to a help buffer for the face.
69 (search-backward list-faces-sample-text
)
70 (help-xref-button 0 'help-face face
)))
72 (put-text-property beg
(1- (point)) 'face face
)
73 ;; Make all face commands default to the proper face
74 ;; anywhere in the line.
75 (put-text-property line-beg
(1- (point)) 'read-face-name face
)
76 ;; If the sample text has multiple lines, line up all of them.
80 (insert-char ?\s max-length
)
82 (goto-char (point-min))))
83 ;; If the *Faces* buffer appears in a different frame,
84 ;; copy all the face definitions from FRAME,
85 ;; so that the display will reflect the frame that was selected.
86 (setq window
(get-buffer-window (get-buffer "*Faces*") t
))
87 (setq disp-frame
(if window
(window-frame window
)
89 (or (eq frame disp-frame
)
90 (dolist (face (face-list))
91 (copy-face face face frame disp-frame
)))))
94 (defun describe-face (face &optional frame
)
95 "Display the properties of face FACE on FRAME.
96 Interactively, FACE defaults to the faces of the character after point
97 and FRAME defaults to the selected frame.
99 If the optional argument FRAME is given, report on face FACE in that frame.
100 If FRAME is t, report on the defaults for face FACE (for new frames).
101 If FRAME is omitted or nil, use the selected frame."
102 (interactive (list (read-face-name "Describe face"
103 (or (face-at-point t
) 'default
)
105 (let* ((attrs '((:family .
"Family")
106 (:foundry .
"Foundry")
111 (:foreground .
"Foreground")
112 (:distant-foreground .
"DistantForeground")
113 (:background .
"Background")
114 (:underline .
"Underline")
115 (:overline .
"Overline")
116 (:strike-through .
"Strike-through")
118 (:inverse-video .
"Inverse")
119 (:stipple .
"Stipple")
121 (:fontset .
"Fontset")
122 (:inherit .
"Inherit")))
123 (max-width (apply #'max
(mapcar #'(lambda (x) (length (cdr x
)))
125 (help-setup-xref (list #'describe-face face
)
126 (called-interactively-p 'interactive
))
128 (setq face
'default
))
129 (if (not (listp face
))
130 (setq face
(list face
)))
131 (with-help-window (help-buffer)
132 (with-current-buffer standard-output
134 (if (stringp f
) (setq f
(intern f
)))
135 ;; We may get called for anonymous faces (i.e., faces
136 ;; expressed using prop-value plists). Those can't be
137 ;; usefully customized, so ignore them.
139 (insert "Face: " (symbol-name f
))
141 (insert " undefined face.\n")
142 (let ((customize-label "customize this face")
144 (insert (concat " (" (propertize "sample" 'font-lock-face f
) ")"))
145 (princ (concat " (" customize-label
")\n"))
146 ;; FIXME not sure how much of this belongs here, and
147 ;; how much in `face-documentation'. The latter is
148 ;; not used much, but needs to return nil for
149 ;; undocumented faces.
150 (let ((alias (get f
'face-alias
))
156 (format "\n %s is an alias for the face `%s'.\n%s"
158 (if (setq obsolete
(get f
'obsolete-face
))
159 (format " This face is obsolete%s; use `%s' instead.\n"
160 (if (stringp obsolete
)
161 (format " since %s" obsolete
)
165 (insert "\nDocumentation:\n"
166 (or (face-documentation face
)
167 "Not documented as a face.")
169 (with-current-buffer standard-output
172 (concat "\\(" customize-label
"\\)") nil t
)
173 (help-xref-button 1 'help-customize-face f
)))
174 (setq file-name
(find-lisp-object-file-name f
'defface
))
176 (princ "Defined in `")
177 (princ (file-name-nondirectory file-name
))
179 ;; Make a hyperlink to the library.
181 (re-search-backward "`\\([^`']+\\)'" nil t
)
182 (help-xref-button 1 'help-face-def f file-name
))
187 (let ((attr (face-attribute f
(car a
) frame
)))
188 (insert (make-string (- max-width
(length (cdr a
))) ?\s
)
189 (cdr a
) ": " (format "%s" attr
))
190 (if (and (eq (car a
) :inherit
)
191 (not (eq attr
'unspecified
)))
192 ;; Make a hyperlink to the parent face.
194 (re-search-backward ": \\([^:]+\\)" nil t
)
195 (help-xref-button 1 'help-face attr
)))