* valid forms of face property: documentation bug, font-lock-{prepend, append}-text-property bug @ 2007-10-29 2:19 Joe Wells [not found] ` <E1J8NOm-0006N7-3M@fencepost.gnu.org> 0 siblings, 1 reply; 4+ messages in thread From: Joe Wells @ 2007-10-29 2:19 UTC (permalink / raw) To: bug-gnu-emacs BUG #1: The documentation in (info "(elisp)Special Properties") is misleading about the legal values of the face property. The documentation says this: `face' You can use the property `face' to control the font and color of text. *Note Faces::, for more information. In the simplest case, the value is a face name. It can also be a list; then each element can be any of these possibilities; * A face name (a symbol or string). * A property list of face attributes. This has the form (KEYWORD VALUE ...), where each KEYWORD is a face attribute name and VALUE is a meaningful value for that attribute. With this feature, you do not need to create a face each time you want to specify a particular attribute for certain text. *Note Face Attributes::. * A cons cell with the form `(foreground-color . COLOR-NAME)' or `(background-color . COLOR-NAME)'. These elements specify just the foreground color or just the background color. *Note Color Names::, for the supported forms of COLOR-NAME. A cons cell of `(foreground-color . COLOR-NAME)' is equivalent to specifying `(:foreground COLOR-NAME)'; likewise for the background. This documentation is misleading. It implies that (1) if the property value is not a list, then it must be a face name (a symbol), and (2) if one wants to use the property list (KEYWORD VALUE ...) form, then one must wrap it inside an extra list. In fact, this impression is wrong. All of these have the same visual effect when inserted in a buffer with font-lock off: #("x" 0 1 (face (:background "green"))) #("x" 0 1 (face ((:background "green")))) #("x" 0 1 (face (background-color . "green"))) #("x" 0 1 (face ((background-color . "green")))) But it gets worse! In fact, the following forms are equivalent: #("x" 0 1 (face (highlight bold (:foreground "red")))) #("x" 0 1 (face (highlight bold :foreground "red"))) #("x" 0 1 (face (highlight bold foreground-color . "red"))) Similarly, these two forms are equivalent: #("x" 0 1 (face (highlight bold))) #("x" 0 1 (face (highlight . bold))) In contrast, these two forms are not equivalent #("x" 0 1 (face ((:foreground "red") highlight bold))) #("x" 0 1 (face (:foreground "red" highlight bold))) Based on my investigations, I think the documentation should say something like this: The value of the face property should be of the form FACE-VALUE, where FACE-VALUE is either of the form PRIMITIVE-FACE-VALUE or (PRIMITIVE-FACE-VALUE . FACE-VALUE). PRIMITIVE-FACE-VALUE is one of these forms: * nil. * A face name (a symbol or string). * A property list of face attributes. ... * A cons cell with the form `(foreground-color . COLOR-NAME)' or `(background-color . COLOR-NAME)'. ... But please don't just use my proposal without verifying it against the actual code which interprets the face property! BUG #2: The font-lock-prepend-text-property and font-lock-append-text-property seem to be designed specifically for use with the face property (despite their documentation not mentioning this aim). They seem to have been written under the assumption that the documentation in the manual for the face property was correct, because they can produce useless results in the presence of the (KEYWORD VALUE ...) form of the face property. Furthermore, they can crash in the presence of the (foreground-color . COLOR) form of the face property. For example, evaluating (let ((s (propertize "#" 'face '(:foreground "red")))) (font-lock-prepend-text-property 0 (length s) 'face 'highlight s) (insert s)) produces sensible visual results (with red foreground and darkseagreen2 background), but evaluating (let ((s (propertize "#" 'face 'highlight))) (font-lock-prepend-text-property 0 (length s) 'face '(:foreground "red") s) (insert s))) fails to use the specified face “highlight”. Even worse, evaluating this expression raises an error: (let ((s (propertize "#" 'face '(foreground-color . "red")))) (font-lock-append-text-property 0 (length s) 'face 'highlight s) (insert s)) If font-lock is the only user of these two functions, this issue may not matter, but it makes it difficult to safely use these functions in other parts of Emacs. And this means there is no easy way to safely add a face to a piece of text that already has one or more face properties. Someone who wants to do this would have to write their own versions of font-lock-{prepend,append}-text-property that do the right thing for all valid values of the face property. I hope this bug report is useful. Joe ====================================================================== In GNU Emacs 22.1.1 (i686-pc-linux-gnu, GTK+ Version 2.8.20) of 2007-06-27 on artemis Windowing system distributor `The X.Org Foundation', version 11.0.70000000 configured using `configure '--prefix=/home/jbw/local2' '--enable-debug' '--disable-nls' '--with-x-toolkit=gtk' 'CFLAGS=-O0 -g3 -ggdb'' Important settings: value of $LC_ALL: nil value of $LC_COLLATE: nil value of $LC_CTYPE: en_US.UTF-8 value of $LC_MESSAGES: nil value of $LC_MONETARY: nil value of $LC_NUMERIC: nil value of $LC_TIME: jbw value of $LANG: nil locale-coding-system: utf-8 default-enable-multibyte-characters: t Minor modes in effect: shell-dirtrack-mode: t TeX-source-specials-mode: t outline-minor-mode: t desktop-save-mode: t url-handler-mode: t tooltip-mode: t mouse-wheel-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t unify-8859-on-encoding-mode: t utf-translate-cjk-mode: t auto-compression-mode: t temp-buffer-resize-mode: t size-indication-mode: t line-number-mode: t transient-mark-mode: t ^ permalink raw reply [flat|nested] 4+ messages in thread
[parent not found: <E1J8NOm-0006N7-3M@fencepost.gnu.org>]
* Re: valid forms of face property: documentation bug, font-lock-{prepend, append}-text-property bug [not found] ` <E1J8NOm-0006N7-3M@fencepost.gnu.org> @ 2007-12-29 6:52 ` Joe Wells 2007-12-30 1:36 ` Richard Stallman 2007-12-30 1:36 ` Richard Stallman 0 siblings, 2 replies; 4+ messages in thread From: Joe Wells @ 2007-12-29 6:52 UTC (permalink / raw) To: rms; +Cc: emacs-devel I hope it is okay that I am adding emacs-devel in the CC header. I have some questions in this e-mail that others might be able to address. (This e-mail conversation began with a bug report sent to bug-gnu-emacs.) Richard Stallman <rms@gnu.org> writes: > BUG #1: The documentation in (info "(elisp)Special Properties") is > misleading about the legal values of the face property. > > I think I decided to deprecate the other kinds of values > which do work. I will change the manual to say so. I think it is not the right solution to deprecate all of the shapes that are not documented in elisp.info. First, I think this face property shape should be documented (and not deprecated): (KEYWORD VALUE ...) It should be documented as an abbreviation of ((KEYWORD VALUE ...)). This face property shape is widely used, and quite convenient. Here are some places code in Emacs uses this shape: * term.el uses face property values like this: (:foreground "red3" :background unspecified) * ses.el uses this face property value: (:box (:line-width 2 :style released-button)) * gdb-ui.el uses this face property value: (:inverse-video t) * There may be other places in Emacs that I did not spot with a quick find-grep. * The code in wid-edit.el uses whatever values its clients provide. Random user 3rd party code might pass the above shapes. * I have not searched through 3rd-party code but I suspect lots of uses of this shape will be found. Second, I think these two shapes should be documented *and* deprecated: (foreground-color . COLOR-NAME) (background-color . COLOR-NAME) There is still some code in Emacs that uses this old shape. For example, the code in facemenu.el makes face properties with values like this: (background-color . "linen") Third, I think this shape should not be documented (or should be explicitly warned against): (PRIMITIVE-FACE-VALUE1 ... PRIMITIVE-FACE-VALUEn . PRIMITIVE-FACE-VALUE) where PRIMITIVE-FACE-VALUE is one of FACENAME or (KEYWORD VALUE ...) or (foreground-color . COLOR-NAME) or (background-color . COLOR-NAME) I also think this shape should not be supported. Except for the special cases of face property lists already described above (a keyword list or a cons beginning with foreground-color or background-color), a face property list should be required to be a proper list (with tail of nil) of primitive face values (as described above). If a face property list is not one of the allowed shapes, then ideally the entire list should have no effect, but certainly at least the non-nil tail should be ignored. By the way, these shapes are in fact currently used in Emacs! The code in startup.el uses face property values like the following in the splash screen: (variable-pitch :foreground "red") (variable-pitch :weight bold) (variable-pitch :slant oblique) (variable-pitch :foreground "darkblue") (variable-pitch :height 0.5) NOTE: I'm briefly changing topic to something I noticed while investigating this. Supposedly, facep returns non-nil for internal face objects, which are special vectors. Do these internal face objects work as face property values? Also, it appears that (facep 'bold) in fact returns one of these internal face objects, but (facep (facep 'bold)) returns nil, so facep seems to violate its own documentation. Is this what is happening? Or is the vector returned by (facep 'bold) not one of the internal face objects? Can anyone answer these questions? (I noticed this because there is code in cus-edit.el that can set a face property value that is anything that passes facep.) > BUG #2: The font-lock-prepend-text-property and > font-lock-append-text-property seem to be designed specifically for > use with the face property (despite their documentation not mentioning > this aim). They seem to have been written under the assumption that > the documentation in the manual for the face property was correct, > > They assume the value has one of the currently recommended forms. > > I wrote a patch to make those functions canonicalize deprecated forms > of the face property. Does it work? Your changes look good. They seem to address the concern I raised. I haven't tested them. Thanks for making these changes! By the way, there are two bad implementations of the same concept in other places in Emacs. They should both be replaced by calls to font-lock-prepend-text-property or should be changed to use font-lock-prepend-text-property. First, rcirc-add-face function in rcirc.el is a bad implementation of the idea of font-lock-prepend-text-property which appears not to properly handle the case where the value of the face property is a symbol. Second, erc-button-add-face in erc-button.el is yet another bad implementation of the same idea that does not handle the case where the face property is a list but is not a list of faces. > However, I'd like to ask: where did you encounter those deprecated > forms? Perhaps we should fix those programs to generate recommended > forms of the value. See comments above. Plus, there will be lots of 3rd-party code. > *** font-lock.el 12 Aug 2007 13:52:30 -0400 1.317.2.3 > --- font-lock.el 28 Dec 2007 14:01:23 -0500 > *************** > *** 1295,1300 **** > --- 1295,1306 ---- > (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)) > + (listp prev) > + (or (keywordp (car prev)) > + (memq (car prev) '(foreground-color background-color))) > + (setq prev (list prev))) > (put-text-property start next prop > (append val (if (listp prev) prev (list prev))) > object) > *************** > *** 1309,1314 **** > --- 1315,1326 ---- > (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)) > + (listp prev) > + (or (keywordp (car prev)) > + (memq (car prev) '(foreground-color background-color))) > + (setq prev (list prev))) > (put-text-property start next prop > (append (if (listp prev) prev (list prev)) val) > object) -- Joe ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: valid forms of face property: documentation bug, font-lock-{prepend, append}-text-property bug 2007-12-29 6:52 ` Joe Wells @ 2007-12-30 1:36 ` Richard Stallman 2007-12-30 1:36 ` Richard Stallman 1 sibling, 0 replies; 4+ messages in thread From: Richard Stallman @ 2007-12-30 1:36 UTC (permalink / raw) To: Joe Wells; +Cc: emacs-devel Your proposal seems pretty good to me. I've written text to document it; what do you think? Meanwhile, I fixed the code in facemenu and startup that generated other formats. In the simplest case, the value is a face name. It can also be a list; then each element can be any of these possibilities; @itemize @bullet @item A face name (a symbol or string). @item A property list of face attributes. This has the form (@var{keyword} @var{value} @dots{}), where each @var{keyword} is a face attribute name and @var{value} is a meaningful value for that attribute. With this feature, you do not need to create a face each time you want to specify a particular attribute for certain text. @xref{Face Attributes}. @item A cons cell with the form @code{(foreground-color . @var{color-name})} or @code{(background-color . @var{color-name})}. These are older, deprecated equivalents for @code{(:foreground @var{color-name})} and @code{(:background @var{color-name})}. Please convert code that uses them. @end itemize It works to use the latter two forms directly as the value of the @code{face} property. ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: valid forms of face property: documentation bug, font-lock-{prepend, append}-text-property bug 2007-12-29 6:52 ` Joe Wells 2007-12-30 1:36 ` Richard Stallman @ 2007-12-30 1:36 ` Richard Stallman 1 sibling, 0 replies; 4+ messages in thread From: Richard Stallman @ 2007-12-30 1:36 UTC (permalink / raw) To: Joe Wells; +Cc: emacs-devel NOTE: I'm briefly changing topic to something I noticed while investigating this. Supposedly, facep returns non-nil for internal face objects, which are special vectors. Do these internal face objects work as face property values? I am not sure the question is important. Also, it appears that (facep 'bold) in fact returns one of these internal face objects, but (facep (facep 'bold)) returns nil, so facep seems to violate its own documentation. Is this what is happening? Or is the vector returned by (facep 'bold) not one of the internal face objects? Can anyone answer these questions? It sounds like a documentation bug to me. I will fix that. By the way, there are two bad implementations of the same concept in other places in Emacs. They should both be replaced by calls to font-lock-prepend-text-property or should be changed to use font-lock-prepend-text-property. First, rcirc-add-face function in rcirc.el is a bad implementation of the idea of font-lock-prepend-text-property which appears not to properly handle the case where the value of the face property is a symbol. Second, erc-button-add-face in erc-button.el is yet another bad implementation of the same idea that does not handle the case where the face property is a list but is not a list of faces. Could you write a fix for that? ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2007-12-30 1:36 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-10-29 2:19 valid forms of face property: documentation bug, font-lock-{prepend, append}-text-property bug Joe Wells [not found] ` <E1J8NOm-0006N7-3M@fencepost.gnu.org> 2007-12-29 6:52 ` Joe Wells 2007-12-30 1:36 ` Richard Stallman 2007-12-30 1:36 ` Richard Stallman
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.