bug#81534: [PATCH] elisp-scope: Improve support for :inherit face specs

zach shaftel via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <[email protected]> Sun, 02 Aug 2026 20:03:09 -0400
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
--=-=-=
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Eshel Yaron <[email protected]> writes:

> Hi,
>
> zach shaftel <[email protected]> writes:
>
>> Tags: patch
>>
>> This patches elisp-scope--match-spec-to-arg to recursively process
>> :inherit face specs, so now even complicated face specs like
>> (:inherit (:inherit (bold (:inherit underline)))) are correctly parsed.
>
> Sounds good, although in (info "(elisp) Face Attributes") I see:
>
>   =E2=80=98:inherit=E2=80=99
>        The name of a face from which to inherit attributes, or a list of
>        face names. [...]
>
> This says that the value of :inherit is always expressed in face names,
> not as a list of face attributes.  And I couldn't find an example of
> such a nested attributes list.  Moreover, evaluating the following form
> indeed yields an "Invalid face inheritance" error:
>
>   (defface f '((t :inherit (bold (:inherit success)))) "")
>
> So I think we should support a list of face names like (bold success),
> but not nested attribute lists.  Makes sense?

Ah I didn't realize that, makes sense. I had tested my example spec as a
face text property and it does render correctly, but I don't think any
sane person would (or should) write that. This patch changes all
:inherit specs to (or (symbol . face) (repeat . (symbol . face))).

>
>> I noticed this after defface forms inheriting from a list of faces
>> weren't being fontified the same as with a single inherited face name.
>> I changed a couple uses of (symbol . face) output specs to just `face'
>> so they utilize this.
>
> Nice.  Could you please also add a test or two?
> See test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el

Added in this patch.

>
>
> Best regards,
>
> Eshel


--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment;
 filename=0001-elisp-scope-Improve-support-for-inherit-face-specs.patch

From 048ce64a75dacfc2b255612519c5f373e2f5400c Mon Sep 17 00:00:00 2001
From: Zach Shaftel <[email protected]>
Date: Sat, 1 Aug 2026 21:33:40 -0400
Subject: [PATCH] elisp-scope: Improve support for :inherit face specs

* lisp/emacs-lisp/elisp-scope.el (elisp-scope--match-spec-to-arg):
Update to support lists of faces in :inherit. Update analyzers for a few
functions to use it.

* test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el:
Extra testing for lists of faces.
---
 lisp/emacs-lisp/elisp-scope.el                 | 11 +++++++----
 .../semantic-highlighting.el                   | 18 +++++++++++++++---
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/lisp/emacs-lisp/elisp-scope.el b/lisp/emacs-lisp/elisp-scope.el
index a81a7dfacaf..cee483043d0 100644
--- a/lisp/emacs-lisp/elisp-scope.el
+++ b/lisp/emacs-lisp/elisp-scope.el
@@ -1818,7 +1818,8 @@ custom-declare-group
 
 (elisp-scope-define-function-analyzer custom-declare-face (face spec doc &rest args)
   (elisp-scope-1 face '(symbol . defface))
-  (elisp-scope-1 spec '(repeat . (cons t . (plist (:inherit . (symbol . face))))))
+  (elisp-scope-1 spec '(repeat . (cons t . (plist (:inherit . (or (symbol . face)
+                                                                  (repeat . (symbol . face))))))))
   (elisp-scope-1 doc)
   (while-let ((kw (car-safe args))
               (bkw (elisp-scope--sym-bare kw))
@@ -1831,7 +1832,7 @@ custom-declare-face
 (elisp-scope-define-function-spec cl-typep (nil cl-type))
 
 (elisp-scope-define-function-spec pulse-momentary-highlight-region
-  (nil nil (symbol . face)))
+  (nil nil face))
 
 (elisp-scope--define-function-analyzer throw (&optional tag val) non-local-exit
   (elisp-scope-1 tag '(symbol . throw-tag))
@@ -2495,10 +2496,12 @@ elisp-scope--match-spec-to-arg
    (if (consp arg)
        (if (keywordp (elisp-scope--sym-bare (car arg)))
            ;; One face, given as a plist of face attributes.
-           '(plist (:inherit . (symbol . face)))
+           '(plist (:inherit . (or (symbol . face)
+                                   (repeat . (symbol . face)))))
          ;; Multiple faces.
          '(repeat . (or (symbol . face)
-                        (plist (:inherit . (symbol . face))))))
+                        (plist (:inherit . (or (symbol . face)
+                                               (repeat . (symbol . face))))))))
      '(symbol . face))
    arg))
 
diff --git a/test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el b/test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el
index 307ca49cc85..43aefb050a7 100644
--- a/test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el
+++ b/test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el
@@ -15,6 +15,16 @@ foo
 ;;                  ^ elisp-bound-variable
   )
 
+(pulse-momentary-highlight-region (point) (point-max)
+;; ^ elisp-function
+;;                                 ^ elisp-function
+;;                                         ^ elisp-function
+                                  (or (and t '(bold success))
+;;                                             ^ elisp-face
+;;                                                  ^ elisp-face
+                                      'warning))
+;;                                     ^ elisp-face
+
 (add-face-text-property
 ;; ^ elisp-function
  (point) (mark)
@@ -163,10 +173,12 @@ baz-opt
 ;;                  ^ elisp-function
 
 (defface foobar
-  '((default :inherit font-lock-function-call-face)
+  '((default :inherit (font-lock-function-call-face error))
 ;;            ^ (elisp-constant font-lock-builtin-face)
-;;                    ^ elisp-face
-    (((background light)) :foreground "#00008b")
+;;                     ^ elisp-face
+;;                                                  ^ elisp-face
+    (((background light)) :foreground "#00008b" :inherit bold)
+;;                                                       ^ elisp-face
     (((background dark))  :foreground "#5c9cff"))
   "Face for highlighting symbol role names in Emacs Lisp code."
   :version "31.1")
-- 
2.55.0


--=-=-=--