# HG changeset patch # User Miles Bader # Date 1214905168 0 # Node ID 2af6e85f13d5067bcd0b1ff899abfb7c282a76d3 # Parent 40d413a9e07b7011db49fd94b6c6df7e1fff6886 Implement display-time wrap/line-prefix feature Revision: emacs@sv.gnu.org/emacs--devo--0--patch-1305 diff -r 40d413a9e07b -r 2af6e85f13d5 doc/lispref/ChangeLog --- 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 + + * text.texi (Special Properties): + * display.texi (Truncation): Add wrap-prefix and line-prefix. + 2008-06-28 Johan Bockgård * display.texi (Other Image Types): Fix copy/paste error; say diff -r 40d413a9e07b -r 2af6e85f13d5 doc/lispref/display.texi --- 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 diff -r 40d413a9e07b -r 2af6e85f13d5 doc/lispref/text.texi --- 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 diff -r 40d413a9e07b -r 2af6e85f13d5 src/ChangeLog --- 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 > + + * 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 * xftfont.c (xftfont_open): Don't call FcConfigSubstitute and diff -r 40d413a9e07b -r 2af6e85f13d5 src/dispextern.h --- 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; diff -r 40d413a9e07b -r 2af6e85f13d5 src/xdisp.c --- 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;