unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Mixing named and anonymous faces in text properties
@ 2019-04-25 18:28 Kévin Le Gouguec
  2019-04-26 16:39 ` Stefan Monnier
  2019-04-26 17:21 ` Kévin Le Gouguec
  0 siblings, 2 replies; 5+ messages in thread
From: Kévin Le Gouguec @ 2019-04-25 18:28 UTC (permalink / raw)
  To: help-gnu-emacs

Hello,

I am trying to understand whether the `face' text property can contain
a list mixing face names with anonymous faces.  The behaviour I
observe seems somewhat inconsistent, unless I am misunderstanding the
documentation.

(elisp)Special Properties says:

> The value of the property can be the following:
>
> • A face name (a symbol or string).
>
> • An anonymous face: a property list of the form ‘(KEYWORD VALUE
>   ...)’, where each KEYWORD is a face attribute name and VALUE
>   is a value for that attribute.
>
> • A list of faces.  Each list element should be either a face
>   name or an anonymous face.  This specifies a face which is an
>   aggregate of the attributes of each of the listed faces.
>   Faces occurring earlier in the list have higher priority.

From what I can tell, in a face list, face names provided *after*
anonymous faces are ignored, even when the anonymous face's attributes
do not overlap with those of the named face.

A (somewhat academic) example (my motivating issue is given further
below):

- C-x b newbuffer RET
- foobarbaz RET foobarbaz RET
- M-: (add-text-properties 1 3 '(face '(italic :weight bold))) RET
- M-: (add-text-properties 11 13 '(face '(:weight bold italic))) RET

On my setup (emacs -Q on master, version 27.0.50, commit c53e7f2),

- "foo" on the first line is displayed in both bold and italic,
- whereas "foo" on the second line only shows up in bold.

Is this expected?  I am asking this on help-gnu-emacs because I am not
sure whether this is a bug, a documentation issue, or me just not
understanding something.


My motivating issue comes from org-mode: if I use strike-through
markers in an Org heading (e.g. "* +some crossed-off heading+"), the
marked words lose the header face.  I reported this problem on the
emacs-orgmode mailing list (with a patch fixing^Wworking around the
issue), but haven't heard back yet.

https://lists.gnu.org/archive/html/emacs-orgmode/2019-04/msg00101.html


Thanks in advance for any pointers!


PS: a last-minute experiment showed that the following works:

- C-x b newerbuffer RET
- foobarbaz RET
- M-: (add-text-properties 1 3 '(face '((:weight bold) italic))) RET

Unfortunately I haven't found a way to make this work in Org, which
does the following in org-do-emphasis-faces:

(pcase-let ((`(,_ ,face ,_) (assoc marker org-emphasis-alist)))
	      (font-lock-prepend-text-property
	       (match-beginning 2) (match-end 2) 'face face)
           …)

Presumably the text already has the org-level-1 face, and this snippet
prepends the (:strike-through t) anonymous face.  I haven't yet dug
into font-lock-prepend-text-property to figure why the property ends
up being

    (:strike-through t org-level-1)

rather than

    ((:strike-through t) org-level-1)

I will take a look later if nobody beats me to it…



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Mixing named and anonymous faces in text properties
  2019-04-25 18:28 Mixing named and anonymous faces in text properties Kévin Le Gouguec
@ 2019-04-26 16:39 ` Stefan Monnier
  2019-04-26 17:21 ` Kévin Le Gouguec
  1 sibling, 0 replies; 5+ messages in thread
From: Stefan Monnier @ 2019-04-26 16:39 UTC (permalink / raw)
  To: help-gnu-emacs

> - M-: (add-text-properties 1 3 '(face '(italic :weight bold))) RET

This is wrong.  It should be

    (add-text-properties 1 3 '(face '(italic (:weight bold))))

I.e. a face property ca hold either a "face" or a list of "face"s,
where "face" can be either a symbol or a plist of face attributes.
So you can set the `face` property to

    italic
    
    (:weight bold)

    (italic (:weight bold))
    
    ((:weight bold) italic)

    (italic)
    
    ...
    
but if the value you used above did what you intended, it's just
a lucky accident.


        Stefan




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Mixing named and anonymous faces in text properties
  2019-04-25 18:28 Mixing named and anonymous faces in text properties Kévin Le Gouguec
  2019-04-26 16:39 ` Stefan Monnier
@ 2019-04-26 17:21 ` Kévin Le Gouguec
  2019-04-29 21:31   ` Stefan Monnier
  1 sibling, 1 reply; 5+ messages in thread
From: Kévin Le Gouguec @ 2019-04-26 17:21 UTC (permalink / raw)
  To: help-gnu-emacs; +Cc: monnier

[-- Attachment #1: Type: text/plain, Size: 1211 bytes --]

(Replying to my own mail since I haven't received Stefan's answer, maybe
because I'm not subscribed to the list)

> > - M-: (add-text-properties 1 3 '(face '(italic :weight bold))) RET
> This is wrong.  It should be
> 
>     (add-text-properties 1 3 '(face '(italic (:weight bold))))
> 
> I.e. a face property ca hold either a "face" or a list of "face"s,
> where "face" can be either a symbol or a plist of face attributes.
> So you can set the `face` property to
> 
>     italic
>     
>     (:weight bold)
> 
>     (italic (:weight bold))
>     
>     ((:weight bold) italic)
> 
>     (italic)
>     
>     ...
>     
> but if the value you used above did what you intended, it's just
> a lucky accident.

Yes, I eventually did figure out that this only works incidentally.  The
only reason I tested this specific invokation is because the problematic
text in Org buffers had

    (:strike-through t org-level-1)

So I replaced the call to font-lock-prepend-text-property with
font-lock-append-text-property as a silly workaround.

I since took a look at font-lock-prepend-text-property and cooked up the
attached patch; if it is correct, I guess font-lock-append-text-property
could use something similar.


[-- Attachment #2: 0001-Refrain-from-splicing-anonymous-faces-in-text-proper.patch --]
[-- Type: text/x-diff, Size: 2445 bytes --]

From 7ddfe61225eaa2409589e61cc3333484fe000492 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= <kevin.legouguec@gmail.com>
Date: Fri, 26 Apr 2019 18:50:48 +0200
Subject: [PATCH] Refrain from splicing anonymous faces in text properties
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Otherwise named faces that follow are not displayed anymore.  E.g. in
an Org buffer with this content:

    * /foo/ *bar* _baz_ +quux+

Before this commit, the 'face property on quux was:

    (:strike-through t org-level-1)

… and the org-level-1 foreground was not displayed.  This commit makes
the 'face property become:

    ((:strike-through t) org-level-1)

… which lets quux display both the strike-through decoration and the
org-level-1 foreground.

* lisp/font-lock.el (font-lock-prepend-text-property):
Wrap anonymous faces in a single-elemnt list so that `append' does not
splice them.
---
 lisp/font-lock.el | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/lisp/font-lock.el b/lisp/font-lock.el
index 1475911195..23135e6445 100644
--- a/lisp/font-lock.el
+++ b/lisp/font-lock.el
@@ -1392,16 +1392,23 @@ font-lock-prepend-text-property
 Arguments PROP and VALUE specify the property and value to prepend to the value
 already in place.  The resulting property values are always lists.
 Optional argument OBJECT is the string or buffer containing the text."
-  (let ((val (if (listp value) value (list value))) next prev)
+  (let ((val (if (listp value) value (list value)))
+        (is-face-prop (memq prop '(face font-lock-face)))
+        next prev)
     (while (/= start end)
       (setq next (next-single-property-change start prop object end)
 	    prev (get-text-property start prop object))
       ;; Canonicalize old forms of face property.
-      (and (memq prop '(face font-lock-face))
+      (and is-face-prop
 	   (listp prev)
 	   (or (keywordp (car prev))
 	       (memq (car prev) '(foreground-color background-color)))
 	   (setq prev (list prev)))
+      ;; Wrap an anonymous face into a single-element list, so that
+      ;; `append' does not splice it.
+      (and is-face-prop
+           (keywordp (car val))
+           (setq val (list val)))
       (put-text-property start next prop
 			 (append val (if (listp prev) prev (list prev)))
 			 object)
-- 
2.20.1


[-- Attachment #3: Type: text/plain, Size: 115 bytes --]


(I was about to send this patch with report-emacs-bug when I saw your
reply; should I go ahead with this report?)

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: Mixing named and anonymous faces in text properties
  2019-04-26 17:21 ` Kévin Le Gouguec
@ 2019-04-29 21:31   ` Stefan Monnier
  2019-04-30  6:11     ` Kévin Le Gouguec
  0 siblings, 1 reply; 5+ messages in thread
From: Stefan Monnier @ 2019-04-29 21:31 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: help-gnu-emacs

> I since took a look at font-lock-prepend-text-property and cooked up the
> attached patch;

Thanks, I installed the slightly simpler version below,


        Stefan


@@ -1392,7 +1392,9 @@ font-lock-prepend-text-property
 Arguments PROP and VALUE specify the property and value to prepend to the value
 already in place.  The resulting property values are always lists.
 Optional argument OBJECT is the string or buffer containing the text."
-  (let ((val (if (listp value) value (list value))) next prev)
+  (let ((val (if (and (listp value) (not (keywordp (car value)))) value
+               (list value)))
+        next prev)
     (while (/= start end)
       (setq next (next-single-property-change start prop object end)
 	    prev (get-text-property start prop object))



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Mixing named and anonymous faces in text properties
  2019-04-29 21:31   ` Stefan Monnier
@ 2019-04-30  6:11     ` Kévin Le Gouguec
  0 siblings, 0 replies; 5+ messages in thread
From: Kévin Le Gouguec @ 2019-04-30  6:11 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Thanks!  Should this change be applied to font-lock-append-text-property
too?

Sometime before your answer, I jumped the gun and wrote a bug report:

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35476

While the first patch is no longer useful, is the test suite worth
keeping around?  If not, no matter, I'm glad I picked up some ERT along
the way.



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-04-30  6:11 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-04-25 18:28 Mixing named and anonymous faces in text properties Kévin Le Gouguec
2019-04-26 16:39 ` Stefan Monnier
2019-04-26 17:21 ` Kévin Le Gouguec
2019-04-29 21:31   ` Stefan Monnier
2019-04-30  6:11     ` Kévin Le Gouguec

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).