[Top][All Lists]

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

Re: reducing defface redundancy

From: Miles Bader
Subject: Re: reducing defface redundancy
Date: 03 Jul 2002 15:38:43 +0900

This email is about my suggestion a while ago for adding a more
convenient grammar for defface; I've appended some of the original
message to the end of this one for reference.

If you recall, the main objection to this was that it might not interact
well with the customize-face UI, in particular with the default mode
where customize-face only presents the current face attributes (as
opposed to the optional `display all face specs' mode, where it presents
the whole conditional face definition, with all the various
possibilities broken out).

After that discussion, my thought was that the proper way to deal with
this is actually simple:  when the user changes some attribute, find
out at what `level' in the defface specification the changed attribute
came from, and apply the user's change there; for any attributes _not_
in the original defface spec, just apply them at the `top' (root)
level.  I think this would be very natural (probably more so than the
current behavior, and certainly no worse).  I also think it would be
simple to implement.

So for instance consider the following example:

   (defface subtle-yet-underlined-mode-line
     '(:inherit mode-line
       :underline t
       (((background light) :background "grey90")
        ((background dark)  :background "grey10"))))

If the user customizes this face, he'll be presented with the _current_
list of face attributes; if he's on a dark-background display, that
will be (:inherit mode-line :underline t :background "grey10").

With the suggested algorithm, if he changes `:inherit mode-line',
`:underline t', or adds a previously unused attribute, that change will
apply to all environments.  However, if he changes `:background ...',
the change will only apply to the relevant branch of the `conditional'
in the defface spec.  So basically the rewritten face spec will look
like the original face-spec except with the user's changes integrated.

What do you think of this suggestion?


Excerpt from original message:

In order to be optimal on disparate display types, many defface clauses
end up having a bunch of clauses with almost the same contents, but
varying one or two attributes.  With the ability to query individual
features, this might become even worse.  So this is a suggestion on a
way to reduce the redundancy of defface specs.

The basic idea is to allow using a lisp vector ([...]) as a kind of `or'
expression in the attribute part of a defface clause.  Each element of
vector is an attribute list, and the first one that is entirely
`supportable' (that is, `display-capable-p' returns true for all of its
attributes) is used.

This way, in many cases common attributes could be factored out, and the
variant parts would become just a vector of possibilities with emacs
choosing the first one that works.  I think this style is very natural,
and might even result in better faces because it would be easier to
write good face specifications (currently, you have to duplicate a lot
of stuff, and it can get tedious to keep everything updated).

Here's one possibility for a more flexible specification that uses the
`or' vector idea above, and I think should be backward compatible:

  SPECS     ::= (CLAUSE ...)
              | (TESTS CLAUSE...)               ; traditional top-level style
              | [SPECS ...]                     ; `or' vector style
              | (TESTS (ATTRIBUTE ...))         ; old style attribute list
  TESTS     ::= t | (TEST ...)
  TEST      ::= (TEST-NAME TEST-ARG...)

In addition to adding the `or' vectors, this makes defface specs
recursive in a way that allows omitting the traditional clause list when
it's not necessary (e.g., when currently you just have `t' as the list
of tests).

Thus _very_ simple defface specs are possible:

  (defface annoying
    '(:foreground "red" :background "yellow"))

which seems very natural.

The `italic' example from my earlier message can become:

  (defface italic
    [(:slant italic) (:underline t)])

And if someone wants a face that's both `emphasized' and yellow, he can do:

  (defface emph-yellow
    '(:foreground "yellow"
      [(:bold t) (:slant italic) (:underline t)]))

which will make either a bold, italic, or underlined yellow face,
depending on what the display is capable of.

Since the new specification is recursive, it's possible to put normal
defface clauses at sub-levels, if that's desirable for factoring out
common attributes; for instance, this is often :

(defface subtle-yet-underlined-mode-line
  '(:inherit mode-line
    :underline t
    (((background light) :background "grey90")
     ((background dark)  :background "grey10"))))

"Most attacks seem to take place at night, during a rainstorm, uphill,
 where four map sheets join."   -- Anon. British Officer in WW I

reply via email to

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