emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [Feature request] face property `raise'


From: Wedler, Christoph
Subject: RE: [Feature request] face property `raise'
Date: Tue, 29 Apr 2003 20:19:12 +0200

address@hidden writes:

 >   A. Don't define different groups of different properties: make all
 >      properties text properties (or group all special = non-user-defined
 >      text properties together)

 >      B. Just provide one abstraction mechanism for all special properties
 >      with the ability to merge the abstract properties (like face
 >      merging).

 > That is an interesting idea.  Could you try writing a precise
 > spec for what it would look like?

 > One complication will be how to extend face customization to handle an
 > unbounded set of properties.  Right now there is a fixed set of face
 > attributes.


OK, below you find some ideas / a draft about this.  It lists potential
problems and possible options how to solve them.  Comments welcome.


 1. the general mechanism: properties, face merging, priorities of
    overlay/text properties, null-value problem

 2. property names for built-in properties (used by the display engine),

 3. backward compatiblity issues (what to do with the current
    properties, especially the properties display/face/category?)

 4. face customization

 5. implementation


1. GENERAL IDEA ----------------------

The general idea is as follows:

 * All properties are "direct" text/overlay properties (as opposed to
   the current display specs, face attributes etc)

 * One special property (`face') specifies a list of faces (i.e.,
   symbols naming the faces).  A face serves as an abstraction
   mechanism, i.e., defines values for some properties.

   As opposed to the current behaviour (new in Emacs-21?), you cannot
   specify individual properties with the text property `face', because
   this is not needed: face attributes are normal "direct" text/overlay
   properties.

   Questions considered below:

    - face/property merging: a property is defined directly and/or in
      more than one face -- which one to choose?

    - how does the face/property merging relate with properties
      specified by overlays?

    - can a face specify the face property? => see 4

 * One special property (`mouse-face) defines additional
   properties to use when the mouse is "near" the characters with the
   `mouse-face property.


A value for the same property can be specified directly and indirectly
via faces.  For each character, the value can be specified by a text
property and by a property of overlays which apply to that character.
The question is: what is the "final" value for that property?

Before we discuss that, let's look at the 3 kind of values for a
property:

 * Absolute values, like :height 120

 * Relative values, like :height 1.2

 * not specified = "null value".  There are three posibilities how this
   can be specified:

     i.   not specified is different to any specified value.  In this
          case, `get-text-property' and friends must allow to
          distinguish this, i.e., this function must have an optional
          DEFAULT argument.

     ii.  nil = not specified.  In this case, we must have specific
          FALSE values for boolean properties like :underline (and even
          some non-booleans like `image'), e.g., :none.

     iii. :null (or some other value) = not specified.  In this case
          `get-text-property' and friends must return that value if a
          properties is not specified

   Option ii is IMHO the best and most Emacs-like (there are only a few
   boolean-like properties), i would also be OK.


The algorithm which determines the "final" property value to apply for a
given character is as follows.

-----------

final_property (charpos, prop) =
  let value1 = if mouse_over (charpos)
                  then mouse_property (charpos, prop)
                  else <unspecified>,
      value2 = specified_prop (charpos, prop),
      value3 = face_property ('default, prop),
      value4 = built_in_prop_value (prop)
  in
     value1 * value2 * value3 * value4

mouse_property (charpos, prop) =
  let mouse_face = specified_prop (charpos, 'mouse-face)
  in
     if mouse_face.specified
        then face_property (mouse_face, prop)
        else <unspecified>

specified_prop (charpos, prop) =
  let values = map (lambda (overlay) =>
                       object_property (overlay, prop),
                    overlays_in_priority_order_at (charpos));
  in
     -- overlay props       -- text props
     reduce ((*), values) * object_property (charpos, prop)

object_property (charpos_or_overlay, prop) =
  let values = map (lambda (face) =>
                       face_property (face, prop),
                    direct_property (charpos_or_overlay, 'face))
  in
     direct_property (charpos_or_overlay, prop) *
        reduce ((*), values)

direct_property : built_in
face_property : built_in

value1 * value2 =                   -- combining values
   if value1.absolutep then
      value1
   elseif value1.unspecifiedp then
      value2
   elseif (value2.unspecifiedp) then
      value1
   elseif (value2.absolutep) then
      combine_to_absolute_value (value1, value2)
   else
      combine_to_relative_value (value1, value2)
   
-----------

Example: let's assume the following line in a buffer

   FFFTTTOOOOOTTTFFF

All characters in the line have the following text properties:

  - mouse-face = highlight which defines background = green
  - face = dark which defines background = grey

The characters TTTOOOOOTTT have the following text properties:

  - background = orange

There is an overlay over the OOOOO with the properties:

  - face = selection which defines background = yellow

Then we'll see the following background colors:

  - if the mouse is over the line, the complete line has a green
    background,
  - otherwise, the OOOOOs have a yellow background, both TTTs have a
    orange background, the rest a grey background

This shows:

  - the most important distinction is mouse vs not mouse,
  - then: overlay (high prio..low prio) vs text property
  - then: direct property vs face properties



2. PROPERTY NAMES -----------

There are properties used by the display engine (built-in properties)
and properties not used by the display engine (user properties).

I see two possibilities for a naming convention for built-in properties
(I do not discuss the individual names of the properties in this mail):

 a. :prop-name, i.e. a symbol starting with a colon,

 b. prop-name, i.e., another symbol

Currently, text/overlay properties use a, face attribute use b, display
properties use a and space properties (grouped in the display spec
`space') use b.

I would suggest to use b:

 - Advantage: more backward compatible (see 3 below),

 - Advantage: a package-specific property might become a built-in
   property in a future release (e.g., fontified)

 - Disadvantage: potential naming conflict of future built-in properties
   with user properties (this is already the case in Emacs)


3. BACKWARD COMPATIBILITY -----------

Of course, if things change in this area, we have the problem of old
ELisp coding.  The individual problems with possible option:

 a. The display property.  The options:

      i. obsolete, ignore it

     ii. obsolete, use it (lower prio than the new direct properties,
         but higher than indirect properties via faces)

 b. direct face attributes in the face property:

      i. setting such a value for the face property is not allowed
         (signals an error)

     ii. obsolete, such list elements in the value of the face property
         are ignored.

    iii. obsolete, use it (with prio as it is now)

 c. category attribute

      i. obsolete, ignore it

     ii. obsolete, use the symbol as an additional face (with lowest
         prio)

 d. changed names of properties: if we use naming convention 1b, we
    would be more backward compatible

 e. ...

The first options are cleaner and will lead to a faster display engine
and probably easier to implement, the latter options are more backward
compatible.


4. FACE CUSTOMIZATION -----------

If faces serve as a general abstraction mechanism, it must be possible
to customize the corresponding face properties:

 - built-in properties can have special support like provided now for
   all face attributes

 - user properties are stored in an alist/plist (symbol |-> sexpr) and
   customized like any variable having such an alist/plist as :type.

We could use the face attribute `face' for the face inherit mechanism.


5. IMPLEMENTATION -----------

Sorry, I cannot say anything here, how much of the current coding can be
reused / has to be rewritten...


- Christoph




reply via email to

[Prev in Thread] Current Thread [Next in Thread]