changeset 96470:2af6e85f13d5

Implement display-time wrap/line-prefix feature Revision: emacs@sv.gnu.org/emacs--devo--0--patch-1305
author Miles Bader <miles@gnu.org>
date Tue, 01 Jul 2008 09:39:28 +0000
parents 40d413a9e07b
children e347ed611dcf
files doc/lispref/ChangeLog doc/lispref/display.texi doc/lispref/text.texi src/ChangeLog src/dispextern.h src/xdisp.c
diffstat 6 files changed, 207 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/doc/lispref/ChangeLog	Tue Jul 01 07:09:03 2008 +0000
+++ b/doc/lispref/ChangeLog	Tue Jul 01 09:39:28 2008 +0000
@@ -1,3 +1,8 @@
+2008-07-01  Miles Bader  <miles@gnu.org>
+
+	* text.texi (Special Properties):
+	* display.texi (Truncation): Add wrap-prefix and line-prefix.
+
 2008-06-28  Johan Bockgård  <bojohan@gnu.org>
 
 	* display.texi (Other Image Types): Fix copy/paste error; say
--- a/doc/lispref/display.texi	Tue Jul 01 07:09:03 2008 +0000
+++ b/doc/lispref/display.texi	Tue Jul 01 09:39:28 2008 +0000
@@ -191,6 +191,29 @@
   When horizontal scrolling (@pxref{Horizontal Scrolling}) is in use in
 a window, that forces truncation.
 
+@defvar wrap-prefix
+If this buffer-local variable is non-@code{nil}, the prefix it defines
+will be added at display-time to the beginning of every continuation
+line due to text wrapping (so if lines are truncated, the wrap-prefix
+is never used).  It may be a string, an image, or a stretch-glyph such
+as used by the `display' text-property.  @xref{Display Property}.
+
+A wrap-prefix may also be specified for regions of text using the
+@code{wrap-prefix} text-property (which takes precedence over the
+value of the @code{wrap-prefix} variable).  @xref{Special Properties}.
+@end defvar
+
+@defvar line-prefix
+If this buffer-local variable is non-@code{nil}, the prefix it defines
+will be added at display-time to the beginning of every
+non-continuation line It may be a string, an image, or a stretch-glyph
+such as used by the `display' text-property.  @xref{Display Property}.
+
+A line-prefix may also be specified for regions of text using the
+@code{line-prefix} text-property (which takes precedence over the
+value of the @code{line-prefix} variable).  @xref{Special Properties}.
+@end defvar
+
   If your buffer contains @emph{very} long lines, and you use
 continuation to display them, just thinking about them can make Emacs
 redisplay slow.  The column computation and indentation functions also
--- a/doc/lispref/text.texi	Tue Jul 01 07:09:03 2008 +0000
+++ b/doc/lispref/text.texi	Tue Jul 01 09:39:28 2008 +0000
@@ -3167,6 +3167,29 @@
 controls the total height of the display line ending in that newline.
 @xref{Line Height}.
 
+@item wrap-prefix
+If text has a @code{wrap-prefix} property, the prefix it defines will
+be added at display-time to the beginning of every continuation line
+due to text wrapping (so if lines are truncated, the wrap-prefix is
+never used).  It may be a string, an image, or a stretch-glyph such as
+used by the @code{display} text-property.  @xref{Display Property}.
+
+A wrap-prefix may also be specified for an entire buffer using the
+@code{wrap-prefix} buffer-local variable (however, a
+@code{wrap-prefix} text-property takes precedence over the value of
+the @code{wrap-prefix} variable).  @xref{Truncation}.
+
+@item line-prefix
+If text has a @code{line-prefix} property, the prefix it defines will
+be added at display-time to the beginning of every non-continuation
+line.  It may be a string, an image, or a stretch-glyph such as used
+by the @code{display} text-property.  @xref{Display Property}.
+
+A line-prefix may also be specified for an entire buffer using the
+@code{line-prefix} buffer-local variable (however, a
+@code{line-prefix} text-property takes precedence over the value of
+the @code{line-prefix} variable).  @xref{Truncation}.
+
 @item modification-hooks
 @cindex change hooks for a character
 @cindex hooks for changing a character
--- a/src/ChangeLog	Tue Jul 01 07:09:03 2008 +0000
+++ b/src/ChangeLog	Tue Jul 01 09:39:28 2008 +0000
@@ -1,3 +1,20 @@
+2008-06-30  Miles Bader  <Miles Bader <miles@gnu.org>>
+
+	* dispextern.h (struct glyph, struct it, struct iterator_stack_entry):
+	Add `avoid_cursor_p' field.
+
+	* xdisp.c (push_it, pop_it): Save/restore avoid_cursor_p field.
+	(set_cursor_from_row): Skip glyphs with avoid_cursor_p set.
+	(append_glyph, append_composite_glyph, produce_image_glyph)
+	(append_stretch_glyph): Initialize avoid_cursor_p
+	(get_it_property): Renamed from `get_line_height_property'.
+	(x_produce_glyphs): Use get_it_property.
+	(handle_line_prefix, push_display_prop): New functions.
+	(display_line, move_it_in_display_line_to): Handle line/wrap prefixes.
+	(Vwrap_prefix, Qwrap_prefix, Vline_prefix, Qline_prefix): New
+	variables.
+	(syms_of_xdisp): Initialize them.
+
 2008-06-30  Kenichi Handa  <handa@m17n.org>
 
 	* xftfont.c (xftfont_open): Don't call FcConfigSubstitute and
--- a/src/dispextern.h	Tue Jul 01 07:09:03 2008 +0000
+++ b/src/dispextern.h	Tue Jul 01 09:39:28 2008 +0000
@@ -366,7 +366,11 @@
      doesn't have a glyph in a font.  */
   unsigned glyph_not_available_p : 1;
 
-#define FACE_ID_BITS	21
+ 
+  /* Non-zero means don't display cursor here.  */
+  unsigned avoid_cursor_p : 1;
+
+#define FACE_ID_BITS	20
 
   /* Face of the glyph.  This is a realized face ID,
      an index in the face cache of the frame.  */
@@ -1887,6 +1891,9 @@
      this is 1 if we're doing an ellipsis.  Otherwise meaningless.  */
   unsigned ellipsis_p : 1;
 
+  /* True means cursor shouldn't be displayed here.  */
+  unsigned avoid_cursor_p : 1;
+
   /* Display table in effect or null for none.  */
   struct Lisp_Char_Table *dp;
 
@@ -1987,6 +1994,7 @@
     unsigned multibyte_p : 1;
     unsigned string_from_display_prop_p : 1;
     unsigned display_ellipsis_p : 1;
+    unsigned avoid_cursor_p : 1;
 
     /* properties from display property that are reset by another display property. */
     Lisp_Object space_width;
--- a/src/xdisp.c	Tue Jul 01 07:09:03 2008 +0000
+++ b/src/xdisp.c	Tue Jul 01 09:39:28 2008 +0000
@@ -262,6 +262,9 @@
    cursor moves into it.  */
 Lisp_Object Vmouse_autoselect_window;
 
+Lisp_Object Vwrap_prefix, Qwrap_prefix;
+Lisp_Object Vline_prefix, Qline_prefix;
+
 /* Non-zero means draw tool bar buttons raised when the mouse moves
    over them.  */
 
@@ -853,6 +856,10 @@
 static int redisplay_mode_lines P_ ((Lisp_Object, int));
 static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
 
+static Lisp_Object get_it_property P_ ((struct it *it, Lisp_Object prop));
+
+static void handle_line_prefix P_ ((struct it *));
+
 #if 0
 static int invisible_text_between_p P_ ((struct it *, int, int));
 #endif
@@ -5210,6 +5217,7 @@
   p->string_nchars = it->string_nchars;
   p->area = it->area;
   p->multibyte_p = it->multibyte_p;
+  p->avoid_cursor_p = it->avoid_cursor_p;
   p->space_width = it->space_width;
   p->font_height = it->font_height;
   p->voffset = it->voffset;
@@ -5271,6 +5279,7 @@
   it->string_nchars = p->string_nchars;
   it->area = p->area;
   it->multibyte_p = p->multibyte_p;
+  it->avoid_cursor_p = p->avoid_cursor_p;
   it->space_width = p->space_width;
   it->font_height = p->font_height;
   it->voffset = p->voffset;
@@ -6677,6 +6686,12 @@
        || (it->method == GET_FROM_DISPLAY_VECTOR		\
 	   && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
 
+  /* If there's a line-/wrap-prefix, handle it.  */
+  if (it->hpos == 0 && it->method == GET_FROM_BUFFER
+      && it->current_y < it->last_visible_y)
+    {
+      handle_line_prefix (it);
+    }
 
   while (1)
     {
@@ -12222,7 +12237,8 @@
   while (glyph < end
 	 && !INTEGERP (glyph->object)
 	 && (!BUFFERP (glyph->object)
-	     || (last_pos = glyph->charpos) < pt_old))
+	     || (last_pos = glyph->charpos) < pt_old
+	     || glyph->avoid_cursor_p))
     {
       if (! STRINGP (glyph->object))
 	{
@@ -16290,6 +16306,78 @@
   return cursor_row_p;
 }
 
+
+
+/* Push the display property PROP so that it will be rendered at the
+   current position in IT.  */
+
+static void
+push_display_prop (struct it *it, Lisp_Object prop)
+{
+  push_it (it);
+
+  /* Never display a cursor on the prefix.  */
+  it->avoid_cursor_p = 1;
+
+  if (STRINGP (prop))
+    {
+      if (SCHARS (prop) == 0)
+	{
+	  pop_it (it);
+	  return;
+	}
+
+      it->string = prop;
+      it->multibyte_p = STRING_MULTIBYTE (it->string);
+      it->current.overlay_string_index = -1;
+      IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
+      it->end_charpos = it->string_nchars = SCHARS (it->string);
+      it->method = GET_FROM_STRING;
+      it->stop_charpos = 0;
+    }
+  else if (CONSP (prop) && EQ (XCAR (prop), Qspace))
+    {
+      it->method = GET_FROM_STRETCH;
+      it->object = prop;
+    }
+#ifdef HAVE_WINDOW_SYSTEM
+  else if (IMAGEP (prop))
+    {
+      it->what = IT_IMAGE;
+      it->image_id = lookup_image (it->f, prop);
+      it->method = GET_FROM_IMAGE;
+    }
+#endif /* HAVE_WINDOW_SYSTEM */
+  else
+    {
+      pop_it (it);		/* bogus display property, give up */
+      return;
+    }
+}
+
+/* See if there's a line- or wrap-prefix, and if so, push it on IT.  */
+
+static void
+handle_line_prefix (struct it *it)
+{
+  Lisp_Object prefix;
+  if (it->continuation_lines_width > 0)
+    {
+      prefix = get_it_property (it, Qwrap_prefix);
+      if (NILP (prefix))
+	prefix = Vwrap_prefix;
+    }
+  else
+    {
+      prefix = get_it_property (it, Qline_prefix);
+      if (NILP (prefix))
+	prefix = Vline_prefix;
+    }
+  if (! NILP (prefix))
+    push_display_prop (it, prefix);
+}
+
+
 
 /* Construct the glyph row IT->glyph_row in the desired matrix of
    IT->w from text at the current position of IT.  See dispextern.h
@@ -16348,6 +16436,13 @@
       move_it_in_display_line_to (it, ZV, it->first_visible_x,
 				  MOVE_TO_POS | MOVE_TO_X);
     }
+  else
+    {
+      /* We only do this when not calling `move_it_in_display_line_to'
+	 above, because move_it_in_display_line_to calls
+	 handle_line_prefix itself.  */
+      handle_line_prefix (it);
+    }
 
   /* Get the initial row height.  This is either the height of the
      text hscrolled, if there is any, or zero.  */
@@ -20310,6 +20405,7 @@
       glyph->descent = it->descent;
       glyph->voffset = it->voffset;
       glyph->type = CHAR_GLYPH;
+      glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
       glyph->left_box_line_p = it->start_of_box_run_p;
       glyph->right_box_line_p = it->end_of_box_run_p;
@@ -20348,6 +20444,7 @@
       glyph->descent = it->descent;
       glyph->voffset = it->voffset;
       glyph->type = COMPOSITE_GLYPH;
+      glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
       glyph->left_box_line_p = it->start_of_box_run_p;
       glyph->right_box_line_p = it->end_of_box_run_p;
@@ -20529,6 +20626,7 @@
 	  glyph->descent = it->descent;
 	  glyph->voffset = it->voffset;
 	  glyph->type = IMAGE_GLYPH;
+	  glyph->avoid_cursor_p = it->avoid_cursor_p;
 	  glyph->multibyte_p = it->multibyte_p;
 	  glyph->left_box_line_p = it->start_of_box_run_p;
 	  glyph->right_box_line_p = it->end_of_box_run_p;
@@ -20573,6 +20671,7 @@
       glyph->descent = height - ascent;
       glyph->voffset = it->voffset;
       glyph->type = STRETCH_GLYPH;
+      glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
       glyph->left_box_line_p = it->start_of_box_run_p;
       glyph->right_box_line_p = it->end_of_box_run_p;
@@ -20740,12 +20839,10 @@
   take_vertical_position_into_account (it);
 }
 
-/* Get line-height and line-spacing property at point.
-   If line-height has format (HEIGHT TOTAL), return TOTAL
-   in TOTAL_HEIGHT.  */
+/* Return the character-property PROP at the current position in IT.  */
 
 static Lisp_Object
-get_line_height_property (it, prop)
+get_it_property (it, prop)
      struct it *it;
      Lisp_Object prop;
 {
@@ -21048,7 +21145,7 @@
 	  it->pixel_width = 0;
 	  it->nglyphs = 0;
 
-	  height = get_line_height_property(it, Qline_height);
+	  height = get_it_property(it, Qline_height);
 	  /* Split (line-height total-height) list */
 	  if (CONSP (height)
 	      && CONSP (XCDR (height))
@@ -21110,7 +21207,7 @@
 		spacing = calc_line_height_property(it, total_height, font, boff, 0);
 	      else
 		{
-		  spacing = get_line_height_property(it, Qline_spacing);
+		  spacing = get_it_property(it, Qline_spacing);
 		  spacing = calc_line_height_property(it, spacing, font, boff, 0);
 		}
 	      if (INTEGERP (spacing))
@@ -24924,6 +25021,32 @@
     doc: /* Non-nil means don't update menu bars.  Internal use only.  */);
   inhibit_menubar_update = 0;
 
+  DEFVAR_LISP ("wrap-prefix", &Vwrap_prefix,
+    doc: /* Prefix added to the beginning of all continuation lines at display-time.
+May be a string, an image, or a stretch-glyph such as used by the
+`display' text-property.
+
+This variable is overridden by any `wrap-prefix' text-property.
+
+To add a prefix to non-continuation lines, use the `line-prefix' variable.  */);
+  Vwrap_prefix = Qnil;
+  staticpro (&Qwrap_prefix);
+  Qwrap_prefix = intern ("wrap-prefix");
+  Fmake_variable_buffer_local (Qwrap_prefix);
+
+  DEFVAR_LISP ("line-prefix", &Vline_prefix,
+    doc: /* Prefix added to the beginning of all non-continuation lines at display-time.
+May be a string, an image, or a stretch-glyph such as used by the
+`display' text-property.
+
+This variable is overridden by any `line-prefix' text-property.
+
+To add a prefix to continuation lines, use the `wrap-prefix' variable.  */);
+  Vline_prefix = Qnil;
+  staticpro (&Qline_prefix);
+  Qline_prefix = intern ("line-prefix");
+  Fmake_variable_buffer_local (Qline_prefix);
+
   DEFVAR_BOOL ("inhibit-eval-during-redisplay", &inhibit_eval_during_redisplay,
     doc: /* Non-nil means don't eval Lisp during redisplay.  */);
   inhibit_eval_during_redisplay = 0;