emacs-devel
[Top][All Lists]
Advanced

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

reducing defface redundancy


From: Miles Bader
Subject: reducing defface redundancy
Date: 20 Apr 2002 12:12:57 +0900

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.  [note that this is one reason why I suggested
using face attribute names/values as the argument to
`display-capable-p']

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

Currently the grammar of defface specs is something like this:

  SPECS     ::= (CLAUSE ...)
  CLAUSE    ::= (TESTS ATTRIBUTE...)
              | (TESTS (ATTRIBUTE ...))         ; old style attribute list
  ATTRIBUTE ::= ATTR-NAME ATTR-VALUE  
  TESTS     ::= t | (TEST ...)
  TEST      ::= (TEST-NAME TEST-ARG...)

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 ...)
  CLAUSE    ::= ATTRIBUTE
              | (TESTS CLAUSE...)               ; traditional top-level style
              | [SPECS ...]                     ; `or' vector style
              | (TESTS (ATTRIBUTE ...))         ; old style attribute list
  ATTRIBUTE ::= ATTR-NAME ATTR-VALUE  
  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"))))

So what'ya think?  It shouldn't be hard to implement, given the
existance of `display-capable-p', it's backward-compatible, and whizzy
as all hell (well, I think so anyway)...

Thanks,

-Miles

-- 
"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]