Fix use-package :custom-face to set face-defface-spec (bug#77928)

By default, `face-set-spec' sets the override face spec, so face
attributes are combined with defaults rather than replacing them.
This was a behavior change that was an apparently unintended
consequence of commit 6b344a9.

Also set the `face-modified' property, which causes Customize to
flag the face as changed outside Customize.

* doc/misc/use-package.texi (Faces): Document the behavior.
* lisp/use-package/use-package-core.el (use-package-handler/:custom-face):
(use-package): Improve docstring to reflect implementation.
* test/lisp/use-package/use-package-tests.el
(use-package-test/:custom-face-1): (use-package-test/:custom-face-2):
(use-package-test/:custom-face-3): (use-package-test/:custom-face-4):
Add tests.
This commit is contained in:
Michael Shields 2025-04-19 12:58:26 -07:00 committed by Eli Zaretskii
parent 0c55cd0e17
commit ebcde0f90f
3 changed files with 46 additions and 9 deletions

View file

@ -1471,7 +1471,7 @@ faces. Example:
(use-package example (use-package example
:custom-face :custom-face
(example-1-face ((t (:foreground "LightPink")))) (example-1-face ((t (:foreground "LightPink"))))
(example-2-face ((t (:foreground "LightGreen"))) face-defspec-spec)) (example-2-face ((t (:foreground "LightGreen")))))
@end group @end group
@group @group
@ -1486,6 +1486,11 @@ faces. Example:
@end group @end group
@end lisp @end lisp
Similarly to @code{:custom} (@pxref{User options}), this allows
configuring customizable faces outside of Customize (@pxref{Saving
Customizations,,, emacs, GNU Emacs Manual}). Using both systems to
configure the same face can lead to confusing results.
@node Hiding minor modes @node Hiding minor modes
@section Hiding minor modes with diminish and delight @section Hiding minor modes with diminish and delight
@cindex hiding minor modes @cindex hiding minor modes

View file

@ -1623,7 +1623,11 @@ no keyword implies `:all'."
(defun use-package-handler/:custom-face (name _keyword args rest state) (defun use-package-handler/:custom-face (name _keyword args rest state)
"Generate use-package custom-face keyword code." "Generate use-package custom-face keyword code."
(use-package-concat (use-package-concat
(mapcar #'(lambda (def) `(apply #'face-spec-set (backquote ,def))) args) (mapcar #'(lambda (def)
`(progn
(apply #'face-spec-set (append (backquote ,def) '(face-defface-spec)))
(put ',(car def) 'face-modified t)))
args)
(use-package-process-keywords name rest state))) (use-package-process-keywords name rest state)))
;;;; :init ;;;; :init
@ -1887,7 +1891,7 @@ Usage:
:custom Call `Custom-set' or `set-default' with each variable :custom Call `Custom-set' or `set-default' with each variable
definition without modifying the Emacs `custom-file'. definition without modifying the Emacs `custom-file'.
(compare with `custom-set-variables'). (compare with `custom-set-variables').
:custom-face Call `custom-set-faces' with each face definition. :custom-face Call `face-spec-set' with each face definition.
:ensure Loads the package using package.el if necessary. :ensure Loads the package using package.el if necessary.
:pin Pin the package to an archive. :pin Pin the package to an archive.
:vc Install the package directly from a version control system :vc Install the package directly from a version control system

View file

@ -1153,7 +1153,12 @@
(match-expansion (match-expansion
(use-package foo :custom-face (foo ((t (:background "#e4edfc"))))) (use-package foo :custom-face (foo ((t (:background "#e4edfc")))))
`(progn `(progn
(apply #'face-spec-set (backquote (foo ((t (:background "#e4edfc")))))) (progn
(apply #'face-spec-set
(append (backquote (foo ((t (:background "#e4edfc")))))
'(face-defface-spec))
)
(put 'foo 'face-modified t))
(require 'foo nil nil)))) (require 'foo nil nil))))
(ert-deftest use-package-test/:custom-face-2 () (ert-deftest use-package-test/:custom-face-2 ()
@ -1163,19 +1168,42 @@
(example-1-face ((t (:foreground "LightPink")))) (example-1-face ((t (:foreground "LightPink"))))
(example-2-face ((t (:foreground "LightGreen"))))) (example-2-face ((t (:foreground "LightGreen")))))
`(progn `(progn
(apply #'face-spec-set (progn
(backquote (example-1-face ((t (:foreground "LightPink")))))) (apply #'face-spec-set
(apply #'face-spec-set (append (backquote (example-1-face ((t (:foreground "LightPink")))))
(backquote (example-2-face ((t (:foreground "LightGreen")))))) '(face-defface-spec)))
(put 'example-1-face 'face-modified t))
(progn
(apply #'face-spec-set
(append (backquote (example-2-face ((t (:foreground "LightGreen")))))
'(face-defface-spec)))
(put 'example-2-face 'face-modified t))
(require 'example nil nil)))) (require 'example nil nil))))
(ert-deftest use-package-test/:custom-face-3 () (ert-deftest use-package-test/:custom-face-3 ()
(match-expansion (match-expansion
(use-package foo :custom-face (foo ((t (:background "#e4edfc"))) face-defspec-spec)) (use-package foo :custom-face (foo ((t (:background "#e4edfc"))) face-defspec-spec))
`(progn `(progn
(apply #'face-spec-set (backquote (foo ((t (:background "#e4edfc"))) face-defspec-spec))) (progn
(apply #'face-spec-set
(append (backquote (foo ((t (:background "#e4edfc"))) face-defspec-spec))
'(face-defface-spec)))
(put 'foo 'face-modified t))
(require 'foo nil nil)))) (require 'foo nil nil))))
(ert-deftest use-package-test/:custom-face-4 ()
(defface use-package-test/base-face '((t (:background "green"))) "")
(defface use-package-test/face '((t (:inherit use-package-test/base-face))) "")
(use-package emacs
:custom-face
(use-package-test/face ((t (:foreground "blue")))))
(should (equal (face-foreground 'use-package-test/face nil t)
"blue"))
(should (equal (face-background 'use-package-test/face nil t)
nil))
(should (equal (get 'use-package-test/face 'face-modified)
t)))
(ert-deftest use-package-test/:init-1 () (ert-deftest use-package-test/:init-1 ()
(match-expansion (match-expansion
(use-package foo :init (init)) (use-package foo :init (init))