* +face-remapping-20040525-2-c.patch
@ 2004-05-25 14:39 Miles Bader
2004-05-25 23:22 ` +face-remapping-20040525-2-c.patch Miles Bader
2004-05-27 12:46 ` +face-remapping-20040525-2-c.patch Richard Stallman
0 siblings, 2 replies; 3+ messages in thread
From: Miles Bader @ 2004-05-25 14:39 UTC (permalink / raw)
[-- Attachment #1: Type: text/plain, Size: 412 bytes --]
Changes:
(1) Face-inheritance and remapping now use the same mechanism face
properties use, so that the merging order and other semantics are
identical
(2) Remapping/inheritance cycle detection is now precise -- cycles are
detected as soon as they occurs, which could avoid problems with
non-absolute attributes
(3) NEWS / lispref entries
(4) Some minor bugs fixed
Patch:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: +face-remapping-20040525-2-c.patch --]
[-- Type: text/x-patch, Size: 49399 bytes --]
2004-05-25 Miles Bader <miles@gnu.org>
* xfaces.c (Vface_remapping_alist): New variable.
(syms_of_xfaces): Initialize it.
(enum named_merge_point_kind, struct named_merge_point): New types.
(push_named_merge_point): New function.
(lface_from_face_name_no_resolve): Renamed from
`lface_from_face_name'. Don't resolve FACE_NAME.
(lface_from_face_name): New function that does the resolve too.
(get_lface_attributes_no_remap): Renamed from `get_lface_attributes'.
Call lface_from_face_name_no_resolve instead of lface_from_face_name.
(get_lface_attributes): New version of this function.
(merge_face_heights): Handle `unspecified' in both directions.
(merge_face_vectors): Take `named_merge_points' arg instead of
`cycle_check'. Call merge_face_ref instead merge_face_inheritance.
(merge_face_inheritance): Function removed.
(merge_named_face): New function.
(merge_face_ref): Renamed from `merge_face_vector_with_property'.
Add new `err_msgs' and `named_merge_points' args. Return error
status. Only print error messages if ERR_MSGS is true. Don't try to
do :inherit attribute validation.
(Ftty_supports_face_attributes_p, Fface_attributes_as_vector)
(compute_char_face, face_at_buffer_position)
(face_at_string_position): Call merge_face_ref instead of
merge_face_vector_with_property.
(lookup_named_face_1): Renamed from `lookup_named_face'. Add new
`signal_p' argument.
(lookup_named_face): New version of this function.
(lookup_basic_face): New function.
(realize_named_face): Call get_lface_attributes_no_remap instead of
get_lface_attributes.
(face_at_buffer_position): Use lookup_basic_face to lookup basic
face-ids. Use merge_named_face instead of doing it manually.
(face_at_string_position): Likewise.
* xdisp.c (init_iterator): Use lookup_basic_face to lookup basic
face-ids.
* fontset.c (Finternal_char_font): Likewise.
* dispextern.h (lookup_basic_face, Vface_remapping_alist): Declare.
M etc/NEWS
M src/ChangeLog
M src/xfaces.c
M src/dispextern.h
M src/fontset.c
M src/xdisp.c
M lispref/display.texi
* modified files
*** orig/etc/NEWS
--- mod/etc/NEWS
***************
*** 2101,2107 ****
total height of the line, i.e. a varying number of pixels are inserted
after each line to make each line exactly that many pixels high.
-
** The buffer local line-spacing variable may now have a float value,
which is used as a height relative to the default frame line height.
--- 2101,2106 ----
***************
*** 2214,2219 ****
--- 2213,2221 ----
If either property is not set, the default `overlay-arrow-string' or
'overlay-arrow-fringe-bitmap' will be used.
+ ** New variable `face-remapping-alist' allows buffer-local face redefinitions
+ by remapping faces to other faces.
+
+++
** New function `line-number-at-pos' returns line number of current
line in current buffer, or if optional buffer position is given, line
*** orig/lispref/display.texi
--- mod/lispref/display.texi
***************
*** 2117,2122 ****
--- 2117,2156 ----
@code{default} face specifies all attributes---in fact, the frame's own
font and colors are synonymous with those of the default face.
+ @defvar face-remapping-alist
+ @tindex face-remapping-alist
+ This variable may be be used to locally change the meaning of face-names,
+ for instance making the @code{default} face a variable-pitch face in a
+ particular buffer. It should be an alist, whose elements have the form
+ @code{(@var{face} @var{remapping@dots{}})}; when the face @var{face} is
+ used at display time, then @var{remapping@dots{}} is used instead.
+ @var{remapping@dots{}} may be any face specification suitable for a
+ @code{face} text property, usually a face name, but also perhaps a property
+ list of face attribute/value pairs; @xref{Special Properties}.
+
+ Alternate face definitions provided by @code{face-remapping-alist}
+ @emph{replace} the remapped faces, they aren't merged with it.
+
+ Recursive face-remapping does not result in an error. Instead, if a
+ remapped face is used recursively, the remapping is ignored for the
+ recursive used, and the ``true'' face used instead.
+
+ Because of the previous two properties, an easy way to @emph{add} to a
+ face's definition using @code{face-remapping-alist}, is simply to
+ recursively include the remapped face it the remapped definition (this is
+ not necessary when remapping the @code{default} face, the result will be
+ eventually merged with the true @code{default} by the display mechanism).
+
+ For example, here's how you could make the default face be the
+ @code{variable-pitch} face in a single buffer, with the height doubled:
+
+ @example
+ (set (make-local-variable 'face-remapping-alist)
+ '((default variable-pitch :height 2.0)))
+ @end example
+
+ @end defvar
+
@node Font Selection
@subsection Font Selection
*** orig/src/dispextern.h
--- mod/src/dispextern.h
***************
*** 2715,2720 ****
--- 2715,2721 ----
int xstricmp P_ ((const unsigned char *, const unsigned char *));
int lookup_face P_ ((struct frame *, Lisp_Object *, int, struct face *));
int lookup_named_face P_ ((struct frame *, Lisp_Object, int));
+ int lookup_basic_face P_ ((struct frame *, int));
int smaller_face P_ ((struct frame *, int, int));
int face_with_height P_ ((struct frame *, int, int));
int lookup_derived_face P_ ((struct frame *, Lisp_Object, int, int));
***************
*** 2731,2736 ****
--- 2732,2739 ----
extern char unspecified_fg[], unspecified_bg[];
void free_realized_multibyte_face P_ ((struct frame *, int));
+ extern Lisp_Object Vface_remapping_alist;
+
/* Defined in xfns.c */
#ifdef HAVE_X_WINDOWS
*** orig/src/fontset.c
--- mod/src/fontset.c
***************
*** 1252,1258 ****
CHECK_NATNUM (ch);
c = XINT (ch);
f = XFRAME (selected_frame);
! face_id = DEFAULT_FACE_ID;
}
else
{
--- 1252,1258 ----
CHECK_NATNUM (ch);
c = XINT (ch);
f = XFRAME (selected_frame);
! face_id = lookup_basic_face (f, DEFAULT_FACE_ID);
}
else
{
*** orig/src/xdisp.c
--- mod/src/xdisp.c
***************
*** 2027,2032 ****
--- 2027,2033 ----
enum face_id base_face_id;
{
int highlight_region_p;
+ enum face_id remapped_base_face_id = base_face_id;
/* Some precondition checks. */
xassert (w != NULL && it != NULL);
***************
*** 2043,2048 ****
--- 2044,2053 ----
free_all_realized_faces (Qnil);
}
+ /* Perhaps remap BASE_FACE_ID to a user-specified alternative. */
+ if (! NILP (Vface_remapping_alist))
+ remapped_base_face_id = lookup_basic_face (XFRAME (w->frame), base_face_id);
+
/* Use one of the mode line rows of W's desired matrix if
appropriate. */
if (row == NULL)
***************
*** 2058,2064 ****
bzero (it, sizeof *it);
it->current.overlay_string_index = -1;
it->current.dpvec_index = -1;
! it->base_face_id = base_face_id;
it->string = Qnil;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
--- 2063,2069 ----
bzero (it, sizeof *it);
it->current.overlay_string_index = -1;
it->current.dpvec_index = -1;
! it->base_face_id = remapped_base_face_id;
it->string = Qnil;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
***************
*** 2242,2252 ****
{
struct face *face;
! it->face_id = base_face_id;
/* If we have a boxed mode line, make the first character appear
with a left box line. */
! face = FACE_FROM_ID (it->f, base_face_id);
if (face->box != FACE_NO_BOX)
it->start_of_box_run_p = 1;
}
--- 2247,2257 ----
{
struct face *face;
! it->face_id = remapped_base_face_id;
/* If we have a boxed mode line, make the first character appear
with a left box line. */
! face = FACE_FROM_ID (it->f, remapped_base_face_id);
if (face->box != FACE_NO_BOX)
it->start_of_box_run_p = 1;
}
***************
*** 3472,3478 ****
/* Value is a multiple of the canonical char height. */
struct face *face;
! face = FACE_FROM_ID (it->f, DEFAULT_FACE_ID);
new_height = (XFLOATINT (it->font_height)
* XINT (face->lface[LFACE_HEIGHT_INDEX]));
}
--- 3477,3484 ----
/* Value is a multiple of the canonical char height. */
struct face *face;
! face = FACE_FROM_ID (it->f,
! lookup_basic_face (it->f, DEFAULT_FACE_ID));
new_height = (XFLOATINT (it->font_height)
* XINT (face->lface[LFACE_HEIGHT_INDEX]));
}
***************
*** 3572,3578 ****
|| EQ (XCAR (prop), Qright_fringe))
&& CONSP (XCDR (prop)))
{
! unsigned face_id = DEFAULT_FACE_ID;
/* Save current settings of IT so that we can restore them
when we are finished with the glyph property value. */
--- 3578,3584 ----
|| EQ (XCAR (prop), Qright_fringe))
&& CONSP (XCDR (prop)))
{
! unsigned face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);
/* Save current settings of IT so that we can restore them
when we are finished with the glyph property value. */
*** orig/src/xfaces.c
--- mod/src/xfaces.c
***************
*** 396,401 ****
--- 396,408 ----
Lisp_Object Vface_new_frame_defaults;
+ /* Alist of face mappings. Each element is either of the form
+ (FACE . NEW-FACE), or (FACE NEW-FACE MERGE-FACE...),
+ where FACE is the named used for lookups, and NEW-FACE is the name
+ that actually gets looked up. If present, MERGE-FACE... are merged
+ during display of FACE, with NEW-FACE. */
+ Lisp_Object Vface_remapping_alist;
+
/* The next ID to assign to Lisp faces. */
static int next_lface_id;
***************
*** 460,465 ****
--- 467,473 ----
struct font_name;
struct table_entry;
+ struct named_merge_point;
static void map_tty_color P_ ((struct frame *, struct face *,
enum lface_attribute_index, int *));
***************
*** 471,477 ****
static int x_face_list_fonts P_ ((struct frame *, char *,
struct font_name **, int, int));
static int font_scalable_p P_ ((struct font_name *));
! static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *, int));
static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *));
static unsigned char *xstrlwr P_ ((unsigned char *));
static void signal_error P_ ((char *, Lisp_Object));
--- 479,486 ----
static int x_face_list_fonts P_ ((struct frame *, char *,
struct font_name **, int, int));
static int font_scalable_p P_ ((struct font_name *));
! static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *,
! int, struct named_merge_point *));
static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *));
static unsigned char *xstrlwr P_ ((unsigned char *));
static void signal_error P_ ((char *, Lisp_Object));
***************
*** 518,528 ****
static int face_numeric_swidth P_ ((Lisp_Object));
static int face_fontset P_ ((Lisp_Object *));
static char *choose_face_font P_ ((struct frame *, Lisp_Object *, int, int, int*));
! static void merge_face_vectors P_ ((struct frame *, Lisp_Object *, Lisp_Object*, Lisp_Object));
! static void merge_face_inheritance P_ ((struct frame *f, Lisp_Object,
! Lisp_Object *, Lisp_Object));
! static void merge_face_vector_with_property P_ ((struct frame *, Lisp_Object *,
! Lisp_Object));
static int set_lface_from_font_name P_ ((struct frame *, Lisp_Object,
Lisp_Object, int, int));
static Lisp_Object lface_from_face_name P_ ((struct frame *, Lisp_Object, int));
--- 527,536 ----
static int face_numeric_swidth P_ ((Lisp_Object));
static int face_fontset P_ ((Lisp_Object *));
static char *choose_face_font P_ ((struct frame *, Lisp_Object *, int, int, int*));
! static void merge_face_vectors P_ ((struct frame *, Lisp_Object *, Lisp_Object*,
! struct named_merge_point *));
! static int merge_face_ref P_ ((struct frame *, Lisp_Object, Lisp_Object *,
! int, struct named_merge_point *));
static int set_lface_from_font_name P_ ((struct frame *, Lisp_Object,
Lisp_Object, int, int));
static Lisp_Object lface_from_face_name P_ ((struct frame *, Lisp_Object, int));
***************
*** 3151,3156 ****
--- 3159,3226 ----
#endif /* GLYPH_DEBUG == 0 */
+ \f
+ /* Face-merge cycle checking. */
+
+ enum named_merge_point_kind
+ {
+ NAMED_MERGE_POINT_NORMAL,
+ NAMED_MERGE_POINT_REMAP
+ };
+
+ /* A `named merge point' is simply a point during face-merging where we
+ look up a face by name. We keep a stack of which named lookups we're
+ currently processing so that we can easily detect cycles, using a
+ linked- list of struct named_merge_point structures, typically
+ allocated on the stack frame of the named lookup functions which are
+ active (so no consing is required). */
+ struct named_merge_point
+ {
+ Lisp_Object face_name;
+ enum named_merge_point_kind named_merge_point_kind;
+ struct named_merge_point *prev;
+ };
+
+
+ /* If a face merging cycle is detected for FACE_NAME, return 0,
+ otherwise add NEW_NAMED_MERGE_POINT, which is initialized using
+ FACE_NAME and NAMED_MERGE_POINT_KIND, as the head of the linked list
+ pointed to by NAMED_MERGE_POINTS, and return 1. */
+
+ static INLINE int
+ push_named_merge_point (struct named_merge_point *new_named_merge_point,
+ Lisp_Object face_name,
+ enum named_merge_point_kind named_merge_point_kind,
+ struct named_merge_point **named_merge_points)
+ {
+ struct named_merge_point *prev;
+
+ for (prev = *named_merge_points; prev; prev = prev->prev)
+ if (EQ (face_name, prev->face_name))
+ {
+ if (prev->named_merge_point_kind == named_merge_point_kind)
+ /* A cycle, so fail. */
+ return 0;
+ else if (prev->named_merge_point_kind == NAMED_MERGE_POINT_REMAP)
+ /* A remap `hides ' any previous normal merge points
+ (because the remap means that it's actually different face),
+ so as we know the current merge point must be normal, we
+ can just assume it's OK. */
+ break;
+ }
+
+ new_named_merge_point->face_name = face_name;
+ new_named_merge_point->named_merge_point_kind = named_merge_point_kind;
+ new_named_merge_point->prev = *named_merge_points;
+
+ *named_merge_points = new_named_merge_point;
+
+ return 1;
+ }
+
+ \f
+
+
/* Resolve face name FACE_NAME. If FACE_NAME is a string, intern it
to make it a symvol. If FACE_NAME is an alias for another face,
return that face's name. */
***************
*** 3178,3201 ****
/* Return the face definition of FACE_NAME on frame F. F null means
! return the definition for new frames. FACE_NAME may be a string or
! a symbol (apparently Emacs 20.2 allowed strings as face names in
! face text properties; Ediff uses that). If FACE_NAME is an alias
! for another face, return that face's definition. If SIGNAL_P is
! non-zero, signal an error if FACE_NAME is not a valid face name.
! If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face
! name. */
!
static INLINE Lisp_Object
! lface_from_face_name (f, face_name, signal_p)
struct frame *f;
Lisp_Object face_name;
int signal_p;
{
Lisp_Object lface;
- face_name = resolve_face_name (face_name);
-
if (f)
lface = assq_no_quit (face_name, f->face_alist);
else
--- 3248,3266 ----
/* Return the face definition of FACE_NAME on frame F. F null means
! return the definition for new frames. FACE_NAME may be a string or a
! symbol (apparently Emacs 20.2 allowed strings as face names in face
! text properties; Ediff uses that). If SIGNAL_P is non-zero, signal
! an error if FACE_NAME is not a valid face name. If SIGNAL_P is zero,
! value is nil if FACE_NAME is not a valid face name. */
static INLINE Lisp_Object
! lface_from_face_name_no_resolve (f, face_name, signal_p)
struct frame *f;
Lisp_Object face_name;
int signal_p;
{
Lisp_Object lface;
if (f)
lface = assq_no_quit (face_name, f->face_alist);
else
***************
*** 3207,3215 ****
--- 3272,3298 ----
signal_error ("Invalid face", face_name);
check_lface (lface);
+
return lface;
}
+ /* Return the face definition of FACE_NAME on frame F. F null means
+ return the definition for new frames. FACE_NAME may be a string or
+ a symbol (apparently Emacs 20.2 allowed strings as face names in
+ face text properties; Ediff uses that). If FACE_NAME is an alias
+ for another face, return that face's definition. If SIGNAL_P is
+ non-zero, signal an error if FACE_NAME is not a valid face name.
+ If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face
+ name. */
+ static INLINE Lisp_Object
+ lface_from_face_name (f, face_name, signal_p)
+ struct frame *f;
+ Lisp_Object face_name;
+ int signal_p;
+ {
+ return lface_from_face_name_no_resolve (f, face_name, signal_p);
+ }
+
/* Get face attributes of face FACE_NAME from frame-local faces on
frame F. Store the resulting attributes in ATTRS which must point
***************
*** 3218,3243 ****
Otherwise, value is zero if FACE_NAME is not a face. */
static INLINE int
! get_lface_attributes (f, face_name, attrs, signal_p)
struct frame *f;
Lisp_Object face_name;
Lisp_Object *attrs;
int signal_p;
{
Lisp_Object lface;
- int success_p;
! lface = lface_from_face_name (f, face_name, signal_p);
! if (!NILP (lface))
{
! bcopy (XVECTOR (lface)->contents, attrs,
! LFACE_VECTOR_SIZE * sizeof *attrs);
! success_p = 1;
}
- else
- success_p = 0;
! return success_p;
}
--- 3301,3365 ----
Otherwise, value is zero if FACE_NAME is not a face. */
static INLINE int
! get_lface_attributes_no_remap (f, face_name, attrs, signal_p)
struct frame *f;
Lisp_Object face_name;
Lisp_Object *attrs;
int signal_p;
{
Lisp_Object lface;
! lface = lface_from_face_name_no_resolve (f, face_name, signal_p);
!
! if (! NILP (lface))
! bcopy (XVECTOR (lface)->contents, attrs,
! LFACE_VECTOR_SIZE * sizeof *attrs);
!
! return !NILP (lface);
! }
!
! /* Get face attributes of face FACE_NAME from frame-local faces on frame
! F. Store the resulting attributes in ATTRS which must point to a
! vector of Lisp_Objects of size LFACE_VECTOR_SIZE. If FACE_NAME is an
! alias for another face, use that face's definition. If SIGNAL_P is
! non-zero, signal an error if FACE_NAME does not name a face.
! Otherwise, value is zero if FACE_NAME is not a face. */
!
! static INLINE int
! get_lface_attributes (f, face_name, attrs, signal_p, named_merge_points)
! struct frame *f;
! Lisp_Object face_name;
! Lisp_Object *attrs;
! int signal_p;
! struct named_merge_point *named_merge_points;
! {
! Lisp_Object face_remapping;
!
! face_name = resolve_face_name (face_name);
!
! /* See if SYMBOL has been remapped to some other face (usually this
! is done buffer-locally). */
! face_remapping = assq_no_quit (face_name, Vface_remapping_alist);
! if (CONSP (face_remapping))
{
! struct named_merge_point named_merge_point;
!
! if (push_named_merge_point (&named_merge_point,
! face_name, NAMED_MERGE_POINT_REMAP,
! &named_merge_points))
! {
! int i;
!
! for (i = 1; i < LFACE_VECTOR_SIZE; ++i)
! attrs[i] = Qunspecified;
!
! return merge_face_ref (f, XCDR (face_remapping), attrs,
! signal_p, named_merge_points);
! }
}
! /* Default case, no remapping. */
! return get_lface_attributes_no_remap (f, face_name, attrs, signal_p);
}
***************
*** 3401,3406 ****
--- 3523,3530 ----
else if (FLOATP (to))
/* relative X relative => relative */
result = make_float (XFLOAT_DATA (from) * XFLOAT_DATA (to));
+ else if (UNSPECIFIEDP (to))
+ result = from;
}
else if (FUNCTIONP (from))
/* FROM is a function, which use to adjust TO. */
***************
*** 3432,3445 ****
completely specified and contain only absolute attributes. Every
specified attribute of FROM overrides the corresponding attribute of
TO; relative attributes in FROM are merged with the absolute value in
! TO and replace it. CYCLE_CHECK is used internally to detect loops in
! face inheritance; it should be Qnil when called from other places. */
static INLINE void
! merge_face_vectors (f, from, to, cycle_check)
struct frame *f;
Lisp_Object *from, *to;
! Lisp_Object cycle_check;
{
int i;
--- 3556,3570 ----
completely specified and contain only absolute attributes. Every
specified attribute of FROM overrides the corresponding attribute of
TO; relative attributes in FROM are merged with the absolute value in
! TO and replace it. NAMED_MERGE_POINTS is used internally to detect
! loops in face inheritance/remapping; it should be 0 when called from
! other places. */
static INLINE void
! merge_face_vectors (f, from, to, named_merge_points)
struct frame *f;
Lisp_Object *from, *to;
! struct named_merge_point *named_merge_points;
{
int i;
***************
*** 3450,3456 ****
other code uses `unspecified' as a generic value for face attributes. */
if (!UNSPECIFIEDP (from[LFACE_INHERIT_INDEX])
&& !NILP (from[LFACE_INHERIT_INDEX]))
! merge_face_inheritance (f, from[LFACE_INHERIT_INDEX], to, cycle_check);
/* If TO specifies a :font attribute, and FROM specifies some
font-related attribute, we need to clear TO's :font attribute
--- 3575,3581 ----
other code uses `unspecified' as a generic value for face attributes. */
if (!UNSPECIFIEDP (from[LFACE_INHERIT_INDEX])
&& !NILP (from[LFACE_INHERIT_INDEX]))
! merge_face_ref (f, from[LFACE_INHERIT_INDEX], to, 0, named_merge_points);
/* If TO specifies a :font attribute, and FROM specifies some
font-related attribute, we need to clear TO's :font attribute
***************
*** 3469,3475 ****
if (!UNSPECIFIEDP (from[i]))
{
if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
! to[i] = merge_face_heights (from[i], to[i], to[i], cycle_check);
else
to[i] = from[i];
}
--- 3594,3601 ----
if (!UNSPECIFIEDP (from[i]))
{
if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
! to[i] = merge_face_heights (from[i], to[i], to[i],
! named_merge_points);
else
to[i] = from[i];
}
***************
*** 3479,3539 ****
to[LFACE_INHERIT_INDEX] = Qnil;
}
! /* Merge face attributes from the face on frame F whose name is
! INHERITS, into the vector of face attributes TO; INHERITS may also be
! a list of face names, in which case they are applied in order.
! CYCLE_CHECK is used to detect loops in face inheritance.
! Returns true if any of the inherited attributes are `font-related'. */
! static void
! merge_face_inheritance (f, inherit, to, cycle_check)
struct frame *f;
! Lisp_Object inherit;
Lisp_Object *to;
! Lisp_Object cycle_check;
{
! if (SYMBOLP (inherit) && !EQ (inherit, Qunspecified))
! /* Inherit from the named face INHERIT. */
! {
! Lisp_Object lface;
!
! /* Make sure we're not in an inheritance loop. */
! cycle_check = CYCLE_CHECK (cycle_check, inherit, 15);
! if (NILP (cycle_check))
! /* Cycle detected, ignore any further inheritance. */
! return;
! lface = lface_from_face_name (f, inherit, 0);
! if (!NILP (lface))
! merge_face_vectors (f, XVECTOR (lface)->contents, to, cycle_check);
! }
! else if (CONSP (inherit))
! /* Handle a list of inherited faces by calling ourselves recursively
! on each element. Note that we only do so for symbol elements, so
! it's not possible to infinitely recurse. */
{
! while (CONSP (inherit))
! {
! if (SYMBOLP (XCAR (inherit)))
! merge_face_inheritance (f, XCAR (inherit), to, cycle_check);
! /* Check for a circular inheritance list. */
! cycle_check = CYCLE_CHECK (cycle_check, inherit, 15);
! if (NILP (cycle_check))
! /* Cycle detected. */
! break;
! inherit = XCDR (inherit);
! }
}
}
! /* Given a Lisp face attribute vector TO and a Lisp object PROP that
! is a face property, determine the resulting face attributes on
! frame F, and store them in TO. PROP may be a single face
! specification or a list of such specifications. Each face
! specification can be
1. A symbol or string naming a Lisp face.
--- 3605,3650 ----
to[LFACE_INHERIT_INDEX] = Qnil;
}
! /* Merge the named face FACE_NAME on frame F, into the vector of face
! attributes TO. NAMED_MERGE_POINTS is used to detect loops in face
! inheritance. Returns true if FACE_NAME is a valid face name and
! merging succeeded. */
! static int
! merge_named_face (f, face_name, to, named_merge_points)
struct frame *f;
! Lisp_Object face_name;
Lisp_Object *to;
! struct named_merge_point *named_merge_points;
{
! struct named_merge_point named_merge_point;
! if (push_named_merge_point (&named_merge_point,
! face_name, NAMED_MERGE_POINT_NORMAL,
! &named_merge_points))
{
! Lisp_Object from[LFACE_VECTOR_SIZE];
! int ok = get_lface_attributes (f, face_name, from, 0, named_merge_points);
! if (ok)
! merge_face_vectors (f, from, to, named_merge_points);
! return ok;
}
+ else
+ return 0;
}
! /* Merge face attributes from the lisp `face reference' FACE_REF on
! frame F into the face attribute vector TO. If ERR_MSGS is non-zero,
! problems with FACE_REF cause an error message to be shown. Return
! non-zero if no errors occurred (regardless of the value of ERR_MSGS).
! NAMED_MERGE_POINTS is used to detect loops in face inheritance or
! list structure; it may be 0 for most callers.
!
! FACE_REF may be a single face specification or a list of such
! specifications. Each face specification can be:
1. A symbol or string naming a Lisp face.
***************
*** 3548,3569 ****
Face specifications earlier in lists take precedence over later
specifications. */
! static void
! merge_face_vector_with_property (f, to, prop)
struct frame *f;
Lisp_Object *to;
! Lisp_Object prop;
{
! if (CONSP (prop))
{
! Lisp_Object first = XCAR (prop);
if (EQ (first, Qforeground_color)
|| EQ (first, Qbackground_color))
{
/* One of (FOREGROUND-COLOR . COLOR) or (BACKGROUND-COLOR
. COLOR). COLOR must be a string. */
! Lisp_Object color_name = XCDR (prop);
Lisp_Object color = first;
if (STRINGP (color_name))
--- 3659,3684 ----
Face specifications earlier in lists take precedence over later
specifications. */
! static int
! merge_face_ref (f, face_ref, to, err_msgs, named_merge_points)
struct frame *f;
+ Lisp_Object face_ref;
Lisp_Object *to;
! int err_msgs;
! struct named_merge_point *named_merge_points;
{
! int ok = 1; /* Succeed without an error? */
!
! if (CONSP (face_ref))
{
! Lisp_Object first = XCAR (face_ref);
if (EQ (first, Qforeground_color)
|| EQ (first, Qbackground_color))
{
/* One of (FOREGROUND-COLOR . COLOR) or (BACKGROUND-COLOR
. COLOR). COLOR must be a string. */
! Lisp_Object color_name = XCDR (face_ref);
Lisp_Object color = first;
if (STRINGP (color_name))
***************
*** 3574,3596 ****
to[LFACE_BACKGROUND_INDEX] = color_name;
}
else
! add_to_log ("Invalid face color", color_name, Qnil);
}
else if (SYMBOLP (first)
&& *SDATA (SYMBOL_NAME (first)) == ':')
{
/* Assume this is the property list form. */
! while (CONSP (prop) && CONSP (XCDR (prop)))
{
! Lisp_Object keyword = XCAR (prop);
! Lisp_Object value = XCAR (XCDR (prop));
if (EQ (keyword, QCfamily))
{
if (STRINGP (value))
to[LFACE_FAMILY_INDEX] = value;
else
! add_to_log ("Invalid face font family", value, Qnil);
}
else if (EQ (keyword, QCheight))
{
--- 3689,3716 ----
to[LFACE_BACKGROUND_INDEX] = color_name;
}
else
! {
! if (err_msgs)
! add_to_log ("Invalid face color", color_name, Qnil);
! ok = 0;
! }
}
else if (SYMBOLP (first)
&& *SDATA (SYMBOL_NAME (first)) == ':')
{
/* Assume this is the property list form. */
! while (CONSP (face_ref) && CONSP (XCDR (face_ref)))
{
! Lisp_Object keyword = XCAR (face_ref);
! Lisp_Object value = XCAR (XCDR (face_ref));
! int err = 0;
if (EQ (keyword, QCfamily))
{
if (STRINGP (value))
to[LFACE_FAMILY_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCheight))
{
***************
*** 3598,3607 ****
merge_face_heights (value, to[LFACE_HEIGHT_INDEX],
Qnil, Qnil);
! if (NILP (new_height))
! add_to_log ("Invalid face font height", value, Qnil);
! else
to[LFACE_HEIGHT_INDEX] = new_height;
}
else if (EQ (keyword, QCweight))
{
--- 3718,3727 ----
merge_face_heights (value, to[LFACE_HEIGHT_INDEX],
Qnil, Qnil);
! if (! NILP (new_height))
to[LFACE_HEIGHT_INDEX] = new_height;
+ else
+ err = 1;
}
else if (EQ (keyword, QCweight))
{
***************
*** 3609,3615 ****
&& face_numeric_weight (value) >= 0)
to[LFACE_WEIGHT_INDEX] = value;
else
! add_to_log ("Invalid face weight", value, Qnil);
}
else if (EQ (keyword, QCslant))
{
--- 3729,3735 ----
&& face_numeric_weight (value) >= 0)
to[LFACE_WEIGHT_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCslant))
{
***************
*** 3617,3623 ****
&& face_numeric_slant (value) >= 0)
to[LFACE_SLANT_INDEX] = value;
else
! add_to_log ("Invalid face slant", value, Qnil);
}
else if (EQ (keyword, QCunderline))
{
--- 3737,3743 ----
&& face_numeric_slant (value) >= 0)
to[LFACE_SLANT_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCunderline))
{
***************
*** 3626,3632 ****
|| STRINGP (value))
to[LFACE_UNDERLINE_INDEX] = value;
else
! add_to_log ("Invalid face underline", value, Qnil);
}
else if (EQ (keyword, QCoverline))
{
--- 3746,3752 ----
|| STRINGP (value))
to[LFACE_UNDERLINE_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCoverline))
{
***************
*** 3635,3641 ****
|| STRINGP (value))
to[LFACE_OVERLINE_INDEX] = value;
else
! add_to_log ("Invalid face overline", value, Qnil);
}
else if (EQ (keyword, QCstrike_through))
{
--- 3755,3761 ----
|| STRINGP (value))
to[LFACE_OVERLINE_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCstrike_through))
{
***************
*** 3644,3650 ****
|| STRINGP (value))
to[LFACE_STRIKE_THROUGH_INDEX] = value;
else
! add_to_log ("Invalid face strike-through", value, Qnil);
}
else if (EQ (keyword, QCbox))
{
--- 3764,3770 ----
|| STRINGP (value))
to[LFACE_STRIKE_THROUGH_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCbox))
{
***************
*** 3656,3662 ****
|| NILP (value))
to[LFACE_BOX_INDEX] = value;
else
! add_to_log ("Invalid face box", value, Qnil);
}
else if (EQ (keyword, QCinverse_video)
|| EQ (keyword, QCreverse_video))
--- 3776,3782 ----
|| NILP (value))
to[LFACE_BOX_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCinverse_video)
|| EQ (keyword, QCreverse_video))
***************
*** 3664,3684 ****
if (EQ (value, Qt) || NILP (value))
to[LFACE_INVERSE_INDEX] = value;
else
! add_to_log ("Invalid face inverse-video", value, Qnil);
}
else if (EQ (keyword, QCforeground))
{
if (STRINGP (value))
to[LFACE_FOREGROUND_INDEX] = value;
else
! add_to_log ("Invalid face foreground", value, Qnil);
}
else if (EQ (keyword, QCbackground))
{
if (STRINGP (value))
to[LFACE_BACKGROUND_INDEX] = value;
else
! add_to_log ("Invalid face background", value, Qnil);
}
else if (EQ (keyword, QCstipple))
{
--- 3784,3804 ----
if (EQ (value, Qt) || NILP (value))
to[LFACE_INVERSE_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCforeground))
{
if (STRINGP (value))
to[LFACE_FOREGROUND_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCbackground))
{
if (STRINGP (value))
to[LFACE_BACKGROUND_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCstipple))
{
***************
*** 3687,3693 ****
if (!NILP (pixmap_p))
to[LFACE_STIPPLE_INDEX] = value;
else
! add_to_log ("Invalid face stipple", value, Qnil);
#endif
}
else if (EQ (keyword, QCwidth))
--- 3807,3813 ----
if (!NILP (pixmap_p))
to[LFACE_STIPPLE_INDEX] = value;
else
! err = 1;
#endif
}
else if (EQ (keyword, QCwidth))
***************
*** 3696,3747 ****
&& face_numeric_swidth (value) >= 0)
to[LFACE_SWIDTH_INDEX] = value;
else
! add_to_log ("Invalid face width", value, Qnil);
}
else if (EQ (keyword, QCinherit))
{
! if (SYMBOLP (value))
! to[LFACE_INHERIT_INDEX] = value;
! else
! {
! Lisp_Object tail;
! for (tail = value; CONSP (tail); tail = XCDR (tail))
! if (!SYMBOLP (XCAR (tail)))
! break;
! if (NILP (tail))
! to[LFACE_INHERIT_INDEX] = value;
! else
! add_to_log ("Invalid face inherit", value, Qnil);
! }
}
else
! add_to_log ("Invalid attribute %s in face property",
! keyword, Qnil);
! prop = XCDR (XCDR (prop));
}
}
else
{
! /* This is a list of face specs. Specifications at the
! beginning of the list take precedence over later
! specifications, so we have to merge starting with the
! last specification. */
! Lisp_Object next = XCDR (prop);
! if (!NILP (next))
! merge_face_vector_with_property (f, to, next);
! merge_face_vector_with_property (f, to, first);
}
}
else
{
! /* PROP ought to be a face name. */
! Lisp_Object lface = lface_from_face_name (f, prop, 0);
! if (NILP (lface))
! add_to_log ("Invalid face text property value: %s", prop, Qnil);
! else
! merge_face_vectors (f, XVECTOR (lface)->contents, to, Qnil);
}
}
--- 3816,3866 ----
&& face_numeric_swidth (value) >= 0)
to[LFACE_SWIDTH_INDEX] = value;
else
! err = 1;
}
else if (EQ (keyword, QCinherit))
{
! /* This is not really very useful; it's just like a
! normal face reference. */
! if (! merge_face_ref (f, value, to,
! err_msgs, named_merge_points))
! err = 1;
}
else
! err = 1;
! if (err)
! {
! add_to_log ("Invalid face attribute %S %S", keyword, value);
! ok = 0;
! }
!
! face_ref = XCDR (XCDR (face_ref));
}
}
else
{
! /* This is a list of face refs. Those at the beginning of the
! list take precedence over what follows, so we have to merge
! from the end backwards. */
! Lisp_Object next = XCDR (face_ref);
!
! if (! NILP (next))
! ok = merge_face_ref (f, next, to, err_msgs, named_merge_points);
!
! if (! merge_face_ref (f, first, to, err_msgs, named_merge_points))
! ok = 0;
}
}
else
{
! /* FACE_REF ought to be a face name. */
! ok = merge_named_face (f, face_ref, to, named_merge_points);
! if (!ok && err_msgs)
! add_to_log ("Invalid face reference: %s", face_ref, Qnil);
}
+
+ return ok;
}
***************
*** 5258,5264 ****
for (i = 0; i < LFACE_VECTOR_SIZE; i++)
attrs[i] = Qunspecified;
! merge_face_vector_with_property (f, attrs, attributes);
/* This function only works on ttys. */
if (!FRAME_TERMCAP_P (f) && !FRAME_MSDOS_P (f))
--- 5377,5383 ----
for (i = 0; i < LFACE_VECTOR_SIZE; i++)
attrs[i] = Qunspecified;
! merge_face_ref (f, attributes, attrs, 1, 0);
/* This function only works on ttys. */
if (!FRAME_TERMCAP_P (f) && !FRAME_MSDOS_P (f))
***************
*** 5734,5744 ****
face couldn't be determined, which might happen if the default face
isn't realized and cannot be realized. */
! int
! lookup_named_face (f, symbol, c)
struct frame *f;
Lisp_Object symbol;
int c;
{
Lisp_Object attrs[LFACE_VECTOR_SIZE];
Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
--- 5853,5864 ----
face couldn't be determined, which might happen if the default face
isn't realized and cannot be realized. */
! static int
! lookup_named_face_1 (f, symbol, c, signal_p)
struct frame *f;
Lisp_Object symbol;
int c;
+ int signal_p;
{
Lisp_Object attrs[LFACE_VECTOR_SIZE];
Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
***************
*** 5751,5762 ****
default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
}
! get_lface_attributes (f, symbol, symbol_attrs, 1);
bcopy (default_face->lface, attrs, sizeof attrs);
! merge_face_vectors (f, symbol_attrs, attrs, Qnil);
return lookup_face (f, attrs, c, NULL);
}
/* Return the ID of the realized ASCII face of Lisp face with ID
LFACE_ID on frame F. Value is -1 if LFACE_ID isn't valid. */
--- 5871,5946 ----
default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
}
! if (! get_lface_attributes (f, symbol, symbol_attrs, signal_p, 0))
! return -1;
!
bcopy (default_face->lface, attrs, sizeof attrs);
! merge_face_vectors (f, symbol_attrs, attrs, 0);
!
return lookup_face (f, attrs, c, NULL);
}
+ /* Return the face id of the realized face for named face SYMBOL on
+ frame F suitable for displaying character C. Value is -1 if the
+ face couldn't be determined, which might happen if the default face
+ isn't realized and cannot be realized. */
+
+ int
+ lookup_named_face (f, symbol, c)
+ struct frame *f;
+ Lisp_Object symbol;
+ int c;
+ {
+ return lookup_named_face_1 (f, symbol, c, 0);
+ }
+
+
+ /* Return the display face-id of the basic face who's canonical face-id
+ is FACE_ID. The return value will usually simply be FACE_ID, unless that
+ basic face has bee remapped via Vface_remapping_alist. This function is
+ conservative: if something goes wrong, it will simply return FACE_ID
+ rather than signal an error. */
+
+ int
+ lookup_basic_face (f, face_id)
+ struct frame *f;
+ int face_id;
+ {
+ Lisp_Object name, mapping;
+ int remapped_face_id;
+
+ if (NILP (Vface_remapping_alist))
+ return face_id; /* Nothing to do. */
+
+ switch (face_id)
+ {
+ case DEFAULT_FACE_ID: name = Qdefault; break;
+ case MODE_LINE_FACE_ID: name = Qmode_line; break;
+ case MODE_LINE_INACTIVE_FACE_ID: name = Qmode_line_inactive; break;
+ case HEADER_LINE_FACE_ID: name = Qheader_line; break;
+ case TOOL_BAR_FACE_ID: name = Qtool_bar; break;
+ case FRINGE_FACE_ID: name = Qfringe; break;
+ case SCROLL_BAR_FACE_ID: name = Qscroll_bar; break;
+ case BORDER_FACE_ID: name = Qborder; break;
+ case CURSOR_FACE_ID: name = Qcursor; break;
+ case MOUSE_FACE_ID: name = Qmouse; break;
+ case MENU_FACE_ID: name = Qmenu; break;
+
+ default:
+ return face_id; /* Give up. */
+ }
+
+ mapping = assq_no_quit (name, Vface_remapping_alist);
+ if (NILP (mapping))
+ return face_id; /* Give up. */
+
+ remapped_face_id = lookup_named_face_1 (f, name, 0, 0);
+ if (remapped_face_id < 0)
+ return face_id; /* Give up. */
+
+ return remapped_face_id;
+ }
+
/* Return the ID of the realized ASCII face of Lisp face with ID
LFACE_ID on frame F. Value is -1 if LFACE_ID isn't valid. */
***************
*** 5890,5898 ****
if (!default_face)
abort ();
! get_lface_attributes (f, symbol, symbol_attrs, 1);
bcopy (default_face->lface, attrs, sizeof attrs);
! merge_face_vectors (f, symbol_attrs, attrs, Qnil);
return lookup_face (f, attrs, c, default_face);
}
--- 6074,6082 ----
if (!default_face)
abort ();
! get_lface_attributes (f, symbol, symbol_attrs, 1, 0);
bcopy (default_face->lface, attrs, sizeof attrs);
! merge_face_vectors (f, symbol_attrs, attrs, 0);
return lookup_face (f, attrs, c, default_face);
}
***************
*** 5905,5913 ****
Lisp_Object lface;
lface = Fmake_vector (make_number (LFACE_VECTOR_SIZE),
Qunspecified);
! merge_face_vector_with_property (XFRAME (selected_frame),
! XVECTOR (lface)->contents,
! plist);
return lface;
}
--- 6089,6096 ----
Lisp_Object lface;
lface = Fmake_vector (make_number (LFACE_VECTOR_SIZE),
Qunspecified);
! merge_face_ref (XFRAME (selected_frame), plist, XVECTOR (lface)->contents,
! 1, 0);
return lface;
}
***************
*** 6753,6759 ****
struct face *new_face;
/* The default face must exist and be fully specified. */
! get_lface_attributes (f, Qdefault, attrs, 1);
check_lface_attrs (attrs);
xassert (lface_fully_specified_p (attrs));
--- 6936,6942 ----
struct face *new_face;
/* The default face must exist and be fully specified. */
! get_lface_attributes_no_remap (f, Qdefault, attrs, 1);
check_lface_attrs (attrs);
xassert (lface_fully_specified_p (attrs));
***************
*** 6766,6773 ****
}
/* Merge SYMBOL's face with the default face. */
! get_lface_attributes (f, symbol, symbol_attrs, 1);
! merge_face_vectors (f, symbol_attrs, attrs, Qnil);
/* Realize the face. */
new_face = realize_face (c, attrs, 0, NULL, id);
--- 6949,6956 ----
}
/* Merge SYMBOL's face with the default face. */
! get_lface_attributes_no_remap (f, symbol, symbol_attrs, 1);
! merge_face_vectors (f, symbol_attrs, attrs, 0);
/* Realize the face. */
new_face = realize_face (c, attrs, 0, NULL, id);
***************
*** 7232,7238 ****
Lisp_Object attrs[LFACE_VECTOR_SIZE];
struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
bcopy (default_face->lface, attrs, sizeof attrs);
! merge_face_vector_with_property (f, attrs, prop);
face_id = lookup_face (f, attrs, ch, NULL);
}
--- 7415,7421 ----
Lisp_Object attrs[LFACE_VECTOR_SIZE];
struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
bcopy (default_face->lface, attrs, sizeof attrs);
! merge_face_ref (f, prop, attrs, 1, 0);
face_id = lookup_face (f, attrs, ch, NULL);
}
***************
*** 7305,7324 ****
*endptr = endpos;
! default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
/* Optimize common cases where we can use the default face. */
if (noverlays == 0
&& NILP (prop)
&& !(pos >= region_beg && pos < region_end))
! return DEFAULT_FACE_ID;
/* Begin with attributes from the default face. */
bcopy (default_face->lface, attrs, sizeof attrs);
/* Merge in attributes specified via text properties. */
if (!NILP (prop))
! merge_face_vector_with_property (f, attrs, prop);
/* Now merge the overlay data. */
noverlays = sort_overlays (overlay_vec, noverlays, w);
--- 7488,7512 ----
*endptr = endpos;
!
! /* Perhaps remap BASE_FACE_ID to a user-specified alternative. */
! if (NILP (Vface_remapping_alist))
! default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
! else
! default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
/* Optimize common cases where we can use the default face. */
if (noverlays == 0
&& NILP (prop)
&& !(pos >= region_beg && pos < region_end))
! return default_face->id;
/* Begin with attributes from the default face. */
bcopy (default_face->lface, attrs, sizeof attrs);
/* Merge in attributes specified via text properties. */
if (!NILP (prop))
! merge_face_ref (f, prop, attrs, 1, 0);
/* Now merge the overlay data. */
noverlays = sort_overlays (overlay_vec, noverlays, w);
***************
*** 7329,7335 ****
prop = Foverlay_get (overlay_vec[i], propname);
if (!NILP (prop))
! merge_face_vector_with_property (f, attrs, prop);
oend = OVERLAY_END (overlay_vec[i]);
oendpos = OVERLAY_POSITION (oend);
--- 7517,7523 ----
prop = Foverlay_get (overlay_vec[i], propname);
if (!NILP (prop))
! merge_face_ref (f, prop, attrs, 1, 0);
oend = OVERLAY_END (overlay_vec[i]);
oendpos = OVERLAY_POSITION (oend);
***************
*** 7340,7347 ****
/* If in the region, merge in the region face. */
if (pos >= region_beg && pos < region_end)
{
! Lisp_Object region_face = lface_from_face_name (f, Qregion, 0);
! merge_face_vectors (f, XVECTOR (region_face)->contents, attrs, Qnil);
if (region_end < endpos)
endpos = region_end;
--- 7528,7534 ----
/* If in the region, merge in the region face. */
if (pos >= region_beg && pos < region_end)
{
! merge_named_face (f, Qregion, attrs, 0);
if (region_end < endpos)
endpos = region_end;
***************
*** 7437,7452 ****
/* Merge in attributes specified via text properties. */
if (!NILP (prop))
! merge_face_vector_with_property (f, attrs, prop);
/* If in the region, merge in the region face. */
if (bufpos
&& bufpos >= region_beg
&& bufpos < region_end)
! {
! Lisp_Object region_face = lface_from_face_name (f, Qregion, 0);
! merge_face_vectors (f, XVECTOR (region_face)->contents, attrs, Qnil);
! }
/* Look up a realized face with the given face attributes,
or realize a new one for ASCII characters. */
--- 7624,7636 ----
/* Merge in attributes specified via text properties. */
if (!NILP (prop))
! merge_face_ref (f, prop, attrs, 1, 0);
/* If in the region, merge in the region face. */
if (bufpos
&& bufpos >= region_beg
&& bufpos < region_end)
! merge_named_face (f, Qregion, attrs, 0);
/* Look up a realized face with the given face attributes,
or realize a new one for ASCII characters. */
***************
*** 7767,7772 ****
--- 7951,7993 ----
ignore. */);
Vface_ignored_fonts = Qnil;
+ DEFVAR_LISP ("face-remapping-alist", &Vface_remapping_alist,
+ doc: /* Alist of face remappings.
+ Each element is of the form:
+
+ (OLD-FACE REPLACEMENT...),
+
+ which causes uses of the face OLD-FACE to use REPLACEMENT... instead.
+ REPLACEMENT... is interpreted the same way the value of a `face' text
+ property is; it may be (1) A face name, (2) A list of face names,
+ (3) A property-list of face attribute/value pairs, or (4) A list of face
+ names intermixed with lists containing face attribute/value pairs.
+
+ Multiple entries in REPLACEMENT... are merged together to form the final
+ result, with faces or attributes earlier in the list taking precedence
+ over those that are later.
+
+ Face-name remapping cycles are suppressed, causing the underlying face
+ to be used instead, so a remapping of the form:
+
+ (OLD-FACE EXTRA-FACE... OLD-FACE)
+
+ or:
+
+ (OLD-FACE (FACE-ATTR VAL ...) OLD-FACE)
+
+ will cause EXTRA-FACE... or (FACE-ATTR VAL ...) to be _merged_ with the
+ existing definition of OLD-FACE. Note that for the default face, this
+ isn't necessary, as every face inherits from the default face.
+
+ Making this variable buffer-local is a good way to allow buffer-specific
+ face definitions. For instance, the mode my-mode could define a face
+ `my-mode-default', and then in the mode setup function, do:
+
+ (set (make-local-variable 'face-remapping-alist)
+ '((default my-mode-default)))). */);
+ Vface_remapping_alist = Qnil;
+
DEFVAR_LISP ("face-font-rescale-alist", &Vface_font_rescale_alist,
doc: /* Alist of fonts vs the rescaling factors.
Each element is a cons (FONT-NAME-PATTERN . RESCALE-RATIO), where
[-- Attachment #3: Type: text/plain, Size: 46 bytes --]
-Miles
--
Would you like fries with that?
[-- Attachment #4: Type: text/plain, Size: 141 bytes --]
_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/emacs-devel
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: +face-remapping-20040525-2-c.patch
2004-05-25 14:39 +face-remapping-20040525-2-c.patch Miles Bader
@ 2004-05-25 23:22 ` Miles Bader
2004-05-27 12:46 ` +face-remapping-20040525-2-c.patch Richard Stallman
1 sibling, 0 replies; 3+ messages in thread
From: Miles Bader @ 2004-05-25 23:22 UTC (permalink / raw)
Whoops, in that patch I forgot to update the comment for the C variable
Vface_remapping_alist (tho the docstring is correct).
Rather than reposting the patch, here's just the updated comment:
/* Alist of face remappings. Each element is of the form:
(OLD-FACE REPLACEMENT...) which causes display of the face OLD-FACE
to use REPLACEMENT... instead. REPLACEMENT... is interpreted the
same way the value of a `face' text property is: it may be (1) A face
name, (2) A list of face names, (3) A property-list of face
attribute/value pairs, or (4) A list of face names intermixed with
lists containing face attribute/value pairs.
Multiple entries in REPLACEMENT... are merged together to form the final
result, with faces or attributes earlier in the list taking precedence
over those that are later.
Face-name remapping cycles are suppressed; recursive references use
the underlying face instead of the remapped face. */
Lisp_Object Vface_remapping_alist;
-Miles
--
Love is a snowmobile racing across the tundra. Suddenly it flips over,
pinning you underneath. At night the ice weasels come. --Nietzsche
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: +face-remapping-20040525-2-c.patch
2004-05-25 14:39 +face-remapping-20040525-2-c.patch Miles Bader
2004-05-25 23:22 ` +face-remapping-20040525-2-c.patch Miles Bader
@ 2004-05-27 12:46 ` Richard Stallman
1 sibling, 0 replies; 3+ messages in thread
From: Richard Stallman @ 2004-05-27 12:46 UTC (permalink / raw)
Cc: emacs-devel
+ This variable may be be used to locally change the meaning of face-names,
This variable is used for buffer-local changes in the appearance of
a face.
+ for instance making the @code{default} face a variable-pitch face in a
+ particular buffer. It should be
Its value should be
an alist, whose elements have the form
+ @code{(@var{face} @var{remapping@dots{}})};
The @dots should be outside of @var. Only the variable name itself
should be inside @var.
+ Alternate face definitions provided by @code{face-remapping-alist}
+ @emph{replace} the remapped faces, they aren't merged with it.
This is not quite grammatical, and isn't entirely clear.
+ Recursive face-remapping does not result in an error. Instead, if a
+ remapped face is used recursively, the remapping is ignored for the
+ recursive used, and the ``true'' face used instead.
I think I understand what that means, but it isn't easy to translate
into concrete terms. Could you write it more concretely? And give an
example?
+ Because of the previous two properties, an easy way to @emph{add} to a
+ face's definition using @code{face-remapping-alist}, is simply to
+ recursively include the remapped face it the remapped definition (this is
+ not necessary when remapping the @code{default} face, the result will be
+ eventually merged with the true @code{default} by the display mechanism).
Could you give an example?
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2004-05-27 12:46 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-25 14:39 +face-remapping-20040525-2-c.patch Miles Bader
2004-05-25 23:22 ` +face-remapping-20040525-2-c.patch Miles Bader
2004-05-27 12:46 ` +face-remapping-20040525-2-c.patch Richard Stallman
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).