[Top][All Lists]

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

Re: Eliminating a couple of independent face definitions

From: Tim Cross
Subject: Re: Eliminating a couple of independent face definitions
Date: Fri, 4 Feb 2011 11:12:27 +1100

On Fri, Feb 4, 2011 at 6:10 AM, Drew Adams <address@hidden> wrote:
> As Drew said, faces need to make sense in their context.
> I just spent some time picking sensible faces from the font-lock-*
> palette for dired+, which by default defines its own static faces.

That's my fault.  I defined the default Dired+ face colors only for light
backgrounds.  I DTRT for Icicles long ago, but I never got around to doing the
same for Dired+.

I've done that now, thanks to your reminder.  (However, I intentionally do not
use face inheritance - see below.)

FWIW, for this I simply use the complements of the light-background default
colors as the dark-background colors.  That is not necessarily ideal, but it at
least is reasonable and consistent.  It is also very quick to do, given some
code (e.g. hexrgb.el or palette.el) that quickly gives you color complements.

Such defaulting could presumably even be built-in (optionally).  For example, we
could allow a dark-background setting to be just a symbol `complement' or
`:complement', which would mean to pick up the `t' setting or the
light-background setting (if present) and use its complement.  Likewise for
light-background setting - whatever is defined would be used for the other
setting, as a complement.  That way a coder could provide a minimal face
definition and still get something reasonable for other background modes.

This could obviously be made more sophisticated, but any such feature could be
an improvement, helping with the problem of coders being lazy and just defining
defaults for one background mode (e.g. light in my case; that is, I designed for
light but defined it as `t', meaning all).


Wrt face inheritance -

Faces are customizable - they are just like user options.  In particular, faces
are _not colors_ and faces are _not constants_.  Color names and RGB hex codes
are essentially constants (even if they can appear slightly different on
different systems etc.).

IMO, it makes sense for a face B to inherit from another face A _only_ when what
is wanted is that customization of A automatically is reflected in B.  When
doing this, we should _always_ expect and assume that A will be customized by
users.  This is true no matter how "basic" A is.

This is why (IMO) it does _not_ make sense in general for faces to inherit from
font-lock faces.  A user will want to customize a font-lock face in order to
affect the appearance of _font-locking_, typically in code.  It does not
generally make sense for a non-font-lock face to automatically become affected
by such customization.  Example: basing a Dired face on a font-lock face would
be perverted (IMO).

My guess is that people who are thinking that inheritance from a few (or even
many) "basic" faces (font-lock or others) is a good idea are not taking
customization of such basic faces by users into account.  IOW, they are not
considering them as _faces_, but rather as constants (e.g. as colors or color

There would be nothing wrong with defining some _constants_ from which faces
could inherit - not defface but something else that indicates the intention of
not being customized.  Nothing wrong with coming up with such "basic faces" that
would never be customized.

But what would that mean?  In this case what is important is not the _usage_ of
the face (it cannot be; that cannot be known), but just its attributes: colors
etc.  IOW, instead of a basic face `highlight' intended for highlighting we
would have basic faces whose names reflect only their appearance:
`red-foreground-bold-boxed' etc.

But though there would be nothing wrong with defining such constant faces, it
would be truly silly.  There is no sense defining such attribute combinations -
no sense defining (uncustomizable) faces for this.  We already have such
constants: the colors themselves (names and #RGB hex codes).  And numbers for
weights etc.  Defining combinations as constants makes little sense.

It is proper to base defface definitions on such constants, but not (in general)
on other faces.  The only time the latter is appropriate (IMO) is when we really
want customizing face A to affect face B which inherits from A.  You do not, I
think, want a Dired face to change just because a user tweaks a font-lock face
to make code comments stand out differently.

The real problem that I'm guessing motivates the (misguided) attempts to base
faces upon each other is that too often the default values of faces are not
defined well enough (see the Dired+ mea culpa above).  Too often too little
effort is devoted to defining the default attributes.

The other problem that has been mentioned is being able to apply different
themes and have the result be more or less reasonable across sets of faces.  I
think that this is not a fundamental problem but is only derivative from not
having good defaults.  Just having reasonable default values that cover both
light and dark backgrounds will go a long way toward eliminating this problem, I

In addition, tools that let users easily change whole sets of faces together,
incrementally, can help.  Do Re Mi offers some help in this way, and other such
tools can be envisaged.

Example: command `doremi-all-faces-fg+' lets you incrementally modify all face
foregrounds at once (hue, saturation, brightness, red, green, and/or blue).
Obviously such a command is limited, but in combination with others it can be a
real help for customizing - and even for defining themes.

I'd be interested in hearing more arguments in favor of faces inheriting from
faces (e.g. "basic" faces).  So far it all seems misguided to me, but perhaps
I'm missing a thing or two.  Please be clear about (a) the _problems_ you are
trying to solve this way, and (b) _how_ you think face inheritance can solve

OK, I'll have a go....

While I appreciate your point of concern regarding the fact inheritance would 'link' faces with little or no apparent connection to each other , possibly resulting in 'odd' results when a user customizes a face, I disagree with most of your assumptions and resulting conclusions regarding motivation.  I am also not convinced that this is a true problem or one of any significant issue. Likewise, while I can understand the argument that the relationship between faces should be based on some obvious/clear relationship, I'm not sure this is a real issue in practice or if it is, it is more a curiosity rather than a problem i.e. wow, that seems like a strange face to inherit from, but not something anyone would spend hours trying to understand. 

One thing I would recommend doing, if possible, would be to spend some time running emacs with a dark background and on a tty. This would likely reveal how bad some default face definitions are and let you see how tedious it is having to customize lots of individual face definitions just to get ones that work. 

As I see it, we want to achieve four main goals. We want to make it easier for developers to set appropriate defaults, we want to get the best default possible for end users, regardless of platform or light/dark background preferences, we want to make it as easy as possible for end users to customize their environment and we want to, if possible, avoid a proliferation of different face definitions, especially when the definitions don't really differ in anything other than name as this makes customizing and theme definition more complex than it needs to be. For all environments, there are a fairly limited set of possible usable face definitions and it would be good if we could have something which allows maximum flexibility, but minimum maintenance and easy customization. 

It was good you pointed out that faces are not just about colour. Sometimes, I think peopoe forget this and only focus on the colour aspect. However, this is understandable as colour is what distinguishes most faces from each other.

We need to acknowledge how difficult it is to define good default faces. Many definitions fail to do this. While your suggestion of using colour compliments can help, I'm not convinced it is always that easy. One problem is that different environments have different sets of colours to work with. For example, if you work under the linux console, you don't have compliments for most of the colours available under other environments, such as X or (I presume) Windows/Mac. The problem is further complicated because most developers won't have access to many of these environments, so can't easil test and design appropriate faces even if motivated to do so. 

I would not argue that inheritance is an ideal solution to this problem, However, I do think it can be part of the solution. Perhaps something along the lines of

 * Establish guidelines on how to use inheritance i.e. how to select which face to inherit from
 * Define a good (not too large) set of base faces. Existing font-lock faces may be sufficient, maybe not. Would need review. 
 * Require all face definitions in core emacs packages to either fully define a face (i.e. definition for dark/light, tty, X mac ms etc) OR inherit from a base face (assuming all base faces are fully defined)
 * Add a section to the manual encouraging developers to either provide a fully defined face or inherit from a base face, but don't just define a single (usually) light background face

The key here is that all faces in core emacs packages would end up with a fully defined face, either explicitly or via inherit. 

One of the reasons I like the use of inherit for face definitions is mainly from an end user perspective. I would rather have faces that are fully defined via inherit, even if that inheritance seems odd, than have a partially defined face which only works if you have a light background or are running under a full gui environment. If, when I change the base face definition, it results in unacceptable changes to some face which inherits from it, I can customize it. My experience has been that this does sometimes happen, but not that often and it is more preferable to fix up the few faces than to spend much more time configuring lots of individual faces. In fact, as the number of individual face definitions has increased, I actaully think we have gone the wrong direction. We have too many faces which are mostly the same. It seems now that every new package is adding its own face definitions and many of them are poorly defined. It now takes much longer for me to establish a consistent set of faces. 

If we required face definitions to either be fully defined or inherited from a base set that are fully defined, we would likely give a much better default experience to end users. Using inheritance also means that when we find a face definition which is poor for a particular environment, we can refine that base definition rather than having to find all similarly poor definitions and updating them individually.  

Using inheritance means that it is easier to make broad changes to face definitions, reducing the time spent in customize and lets you then tweak those specific faces which don't quite work. So, using your example, if someone changed the base face that dired+ uses, either they will find the result in dired+ acceptable or they can then tweak that face further. The alternative is that it would be necessary to customize both faces, even when you are going to set them to the same value. The reality is that there are a limited set of good faces and you will usually end up with the same face definition being used in multiple roles. Frequently, those roles have nothing to do with each other. This doesn't matter as the contexts are completely different. From an end user perspective, it is irrelevant that compiler messages inherit from font-lock-string - all the end user sees is that compiler messages use a default face that is green, which may be exactly the same as strings in their code, but so what. 

Of course, much of this may become less of an issue now that emacs has support for themes. though there isn't yet any environment specific themes i.e tty, terminal etc. 


reply via email to

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