Mercurial > emacs
changeset 96238:1bb123f7f691
(Vtruncate_partial_width_windows): New Lisp_Object, replacing
truncate_partial_width_windows.
(init_iterator): If Vtruncate_partial_width_windows is an integer,
truncate only if the window width is below that integer.
(start_display. resize_mini_window, produce_stretch_glyph)
(display_string, move_it_in_display_line_to): Use line_wrap.
(back_to_previous_visible_line_start, reseat_1): Reset
string_from_display_prop_p.
(display_line): Extend default face to end of line when wrapping.
(display_line, move_it_in_display_line_to): Add ability
to wrap continued lines at word boundaries.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Tue, 24 Jun 2008 18:00:20 +0000 |
parents | 9687aec12c3f |
children | 2f2e5059ea17 |
files | src/xdisp.c |
diffstat | 1 files changed, 200 insertions(+), 57 deletions(-) [+] |
line wrap: on
line diff
--- a/src/xdisp.c Tue Jun 24 17:58:50 2008 +0000 +++ b/src/xdisp.c Tue Jun 24 18:00:20 2008 +0000 @@ -420,7 +420,7 @@ /* Nonzero means truncate lines in all windows less wide than the frame. */ -int truncate_partial_width_windows; +Lisp_Object Vtruncate_partial_width_windows; /* A flag to control how to display unibyte 8-bit character. */ @@ -2634,19 +2634,27 @@ it->tab_width = 8; /* Are lines in the display truncated? */ - it->truncate_lines_p - = (base_face_id != DEFAULT_FACE_ID - || XINT (it->w->hscroll) - || (truncate_partial_width_windows - && !WINDOW_FULL_WIDTH_P (it->w)) - || !NILP (current_buffer->truncate_lines)); + if (base_face_id != DEFAULT_FACE_ID + || XINT (it->w->hscroll) + || (! WINDOW_FULL_WIDTH_P (it->w) + && ((!NILP (Vtruncate_partial_width_windows) + && !INTEGERP (Vtruncate_partial_width_windows)) + || (INTEGERP (Vtruncate_partial_width_windows) + && (WINDOW_TOTAL_COLS (it->w) + < XINT (Vtruncate_partial_width_windows)))))) + it->line_wrap = TRUNCATE; + else if (NILP (current_buffer->truncate_lines)) + it->line_wrap = NILP (current_buffer->word_wrap) + ? WINDOW_WRAP : WORD_WRAP; + else + it->line_wrap = TRUNCATE; /* Get dimensions of truncation and continuation glyphs. These are displayed as fringe bitmaps under X, so we don't need them for such frames. */ if (!FRAME_WINDOW_P (it->f)) { - if (it->truncate_lines_p) + if (it->line_wrap == TRUNCATE) { /* We will need the truncation glyph. */ xassert (it->glyph_row == NULL); @@ -2696,7 +2704,7 @@ for window-based redisplay. */ if (!FRAME_WINDOW_P (it->f)) { - if (it->truncate_lines_p) + if (it->line_wrap == TRUNCATE) it->last_visible_x -= it->truncation_pixel_width; else it->last_visible_x -= it->continuation_pixel_width; @@ -2769,7 +2777,7 @@ /* Don't reseat to previous visible line start if current start position is in a string or image. */ - if (it->method == GET_FROM_BUFFER && !it->truncate_lines_p) + if (it->method == GET_FROM_BUFFER && it->line_wrap != TRUNCATE) { int start_at_line_beg_p; int first_y = it->current_y; @@ -2794,7 +2802,7 @@ taken us to the start of the continuation line but to the end of the continued line. */ if (it->current_x > 0 - && !it->truncate_lines_p /* Lines are continued. */ + && it->line_wrap != TRUNCATE /* Lines are continued. */ && (/* And glyph doesn't fit on the line. */ new_x > it->last_visible_x /* Or it fits exactly and we're on a window @@ -5432,6 +5440,7 @@ pos = --IT_CHARPOS (it2); --IT_BYTEPOS (it2); it2.sp = 0; + it2.string_from_display_prop_p = 0; if (handle_display_prop (&it2) == HANDLED_RETURN && !NILP (val = get_char_property_and_overlay (make_number (pos), Qdisplay, Qnil, &overlay)) @@ -5582,6 +5591,7 @@ IT_STRING_CHARPOS (*it) = -1; IT_STRING_BYTEPOS (*it) = -1; it->string = Qnil; + it->string_from_display_prop_p = 0; it->method = GET_FROM_BUFFER; it->object = it->w->buffer; it->area = TEXT_AREA; @@ -6643,11 +6653,20 @@ { enum move_it_result result = MOVE_UNDEFINED; struct glyph_row *saved_glyph_row; + struct it wrap_it, atpos_it; + int may_wrap = 0; /* Don't produce glyphs in produce_glyphs. */ saved_glyph_row = it->glyph_row; it->glyph_row = NULL; + /* Use wrap_it to save a copy of IT wherever a word wrap could + occur. Use atpos_it to save a copy of IT at the desired + position, if found, so that we can scan ahead and check if the + word later overshoots the window edge. */ + wrap_it.sp = -1; + atpos_it.sp = -1; + #define BUFFER_POS_REACHED_P() \ ((op & MOVE_TO_POS) != 0 \ && BUFFERP (it->object) \ @@ -6667,36 +6686,77 @@ && it->method == GET_FROM_BUFFER && IT_CHARPOS (*it) > to_charpos) { - result = MOVE_POS_MATCH_OR_ZV; - break; + if (it->line_wrap == WORD_WRAP) + { + /* If wrap_it is valid, the current position might be in + a word that is wrapped to the next line, so continue + to see if that happens. */ + if (wrap_it.sp < 0) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } + if (atpos_it.sp < 0) + atpos_it = *it; + } + else + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } } /* Stop when ZV reached. We used to stop here when TO_CHARPOS reached as well, but that is too soon if this glyph does not fit on this line. So we handle it explicitly below. */ - if (!get_next_display_element (it) - || (it->truncate_lines_p - && BUFFER_POS_REACHED_P ())) + if (!get_next_display_element (it)) { result = MOVE_POS_MATCH_OR_ZV; break; } + if (it->line_wrap == TRUNCATE) + { + if (BUFFER_POS_REACHED_P ()) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } + } + else + { + /* Remember the line height so far in case the next element + doesn't fit on the line. */ + ascent = it->max_ascent; + descent = it->max_descent; + + if (it->line_wrap == WORD_WRAP) + { + if (it->what == IT_CHARACTER + && (it->c == ' ' || it->c == '\t')) + may_wrap = 1; + else if (may_wrap) + { + /* We are done if the position is already found. */ + if (atpos_it.sp >= 0) + { + *it = atpos_it; + atpos_it.sp = -1; + goto buffer_pos_reached; + } + wrap_it = *it; + may_wrap = 0; + } + } + } + /* The call to produce_glyphs will get the metrics of the - display element IT is loaded with. We record in x the - x-position before this display element in case it does not - fit on the line. */ + display element IT is loaded with. Record the x-position + before this display element, in case it doesn't fit on the + line. */ x = it->current_x; - /* Remember the line height so far in case the next element doesn't - fit on the line. */ - if (!it->truncate_lines_p) - { - ascent = it->max_ascent; - descent = it->max_descent; - } - PRODUCE_GLYPHS (it); if (it->area != TEXT_AREA) @@ -6740,19 +6800,30 @@ if ((op & MOVE_TO_X) && new_x > to_x) { if (BUFFER_POS_REACHED_P ()) - goto buffer_pos_reached; + { + if (it->line_wrap == WORD_WRAP) + { + if (wrap_it.sp < 0) + goto buffer_pos_reached; + if (atpos_it.sp < 0) + atpos_it = *it; + } + else + goto buffer_pos_reached; + } it->current_x = x; result = MOVE_X_REACHED; break; } - else if (/* Lines are continued. */ - !it->truncate_lines_p - && (/* And glyph doesn't fit on the line. */ - new_x > it->last_visible_x - /* Or it fits exactly and we're on a window - system frame. */ - || (new_x == it->last_visible_x - && FRAME_WINDOW_P (it->f)))) + + if (/* Lines are continued. */ + it->line_wrap != TRUNCATE + && (/* And glyph doesn't fit on the line. */ + new_x > it->last_visible_x + /* Or it fits exactly and we're on a window + system frame. */ + || (new_x == it->last_visible_x + && FRAME_WINDOW_P (it->f)))) { if (/* IT->hpos == 0 means the very first glyph doesn't fit on the line, e.g. a wide image. */ @@ -6811,24 +6882,37 @@ it->max_descent = descent; } + if (wrap_it.sp >= 0) + { + *it = wrap_it; + atpos_it.sp = -1; + } + TRACE_MOVE ((stderr, "move_it_in: continued at %d\n", IT_CHARPOS (*it))); result = MOVE_LINE_CONTINUED; break; } - else if (BUFFER_POS_REACHED_P ()) - goto buffer_pos_reached; - else if (new_x > it->first_visible_x) + + if (BUFFER_POS_REACHED_P ()) + { + if (it->line_wrap == WORD_WRAP) + { + if (wrap_it.sp < 0) + goto buffer_pos_reached; + if (atpos_it.sp < 0) + atpos_it = *it; + } + else + goto buffer_pos_reached; + } + + if (new_x > it->first_visible_x) { /* Glyph is visible. Increment number of glyphs that would be displayed. */ ++it->hpos; } - else - { - /* Glyph is completely off the left margin of the display - area. Nothing to do. */ - } } if (result != MOVE_UNDEFINED) @@ -6867,7 +6951,7 @@ /* Stop if lines are truncated and IT's current x-position is past the right edge of the window now. */ - if (it->truncate_lines_p + if (it->line_wrap == TRUNCATE && it->current_x >= it->last_visible_x) { #ifdef HAVE_WINDOW_SYSTEM @@ -6893,6 +6977,11 @@ #undef BUFFER_POS_REACHED_P + /* If we scanned beyond to_pos and didn't find a point to wrap at, + return iterator at to_pos. */ + if (atpos_it.sp >= 0) + *it = atpos_it; + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -8555,7 +8644,7 @@ max_height = min (total_height, max_height); /* Find out the height of the text in the window. */ - if (it.truncate_lines_p) + if (it.line_wrap == TRUNCATE) height = 1; else { @@ -15997,7 +16086,8 @@ && it->glyph_row->displays_text_p && face->box == FACE_NO_BOX && face->background == FRAME_BACKGROUND_PIXEL (f) - && !face->stipple) + && !face->stipple + && it->line_wrap != WORD_WRAP) return; /* Set the glyph row flag indicating that the face of the last glyph @@ -16212,6 +16302,11 @@ { struct glyph_row *row = it->glyph_row; Lisp_Object overlay_arrow_string; + struct it wrap_it; + int may_wrap = 0, wrap_x; + int wrap_row_used = -1, wrap_row_ascent, wrap_row_height; + int wrap_row_phys_ascent, wrap_row_phys_height; + int wrap_row_extra_line_spacing; /* We always start displaying at hpos zero even if hscrolled. */ xassert (it->hpos == 0 && it->current_x == 0); @@ -16306,12 +16401,31 @@ /* Remember the line height so far in case the next element doesn't fit on the line. */ - if (!it->truncate_lines_p) + if (it->line_wrap != TRUNCATE) { ascent = it->max_ascent; descent = it->max_descent; phys_ascent = it->max_phys_ascent; phys_descent = it->max_phys_descent; + + if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA) + { + if (it->what == IT_CHARACTER + && (it->c == ' ' || it->c == '\t')) + may_wrap = 1; + else if (may_wrap) + { + wrap_it = *it; + wrap_x = x; + wrap_row_used = row->used[TEXT_AREA]; + wrap_row_ascent = row->ascent; + wrap_row_height = row->height; + wrap_row_phys_ascent = row->phys_ascent; + wrap_row_phys_height = row->phys_height; + wrap_row_extra_line_spacing = row->extra_line_spacing; + may_wrap = 0; + } + } } PRODUCE_GLYPHS (it); @@ -16371,7 +16485,7 @@ new_x = x + glyph->pixel_width; if (/* Lines are continued. */ - !it->truncate_lines_p + it->line_wrap != TRUNCATE && (/* Glyph doesn't fit on the line. */ new_x > it->last_visible_x /* Or it fits exactly on a window system frame. */ @@ -16412,6 +16526,8 @@ } } #endif /* HAVE_WINDOW_SYSTEM */ + if (wrap_row_used > 0) + goto back_to_wrap; } } else if (CHAR_GLYPH_PADDING_P (*glyph) @@ -16439,6 +16555,26 @@ it->max_phys_ascent = phys_ascent; it->max_phys_descent = phys_descent; } + else if (wrap_row_used > 0) + { + back_to_wrap: + *it = wrap_it; + it->continuation_lines_width += wrap_x; + row->used[TEXT_AREA] = wrap_row_used; + row->ascent = wrap_row_ascent; + row->height = wrap_row_height; + row->phys_ascent = wrap_row_phys_ascent; + row->phys_height = wrap_row_phys_height; + row->extra_line_spacing = wrap_row_extra_line_spacing; + row->continued_p = 1; + row->ends_at_zv_p = 0; + row->exact_window_width_line_p = 0; + it->continuation_lines_width += x; + + /* Make sure that a non-default face is extended + up to the right margin of the window. */ + extend_face_to_end_of_line (it); + } else if (it->c == '\t' && FRAME_WINDOW_P (it->f)) { /* A TAB that extends past the right edge of the @@ -16554,7 +16690,7 @@ /* If we truncate lines, we are done when the last displayed glyphs reach past the right margin of the window. */ - if (it->truncate_lines_p + if (it->line_wrap == TRUNCATE && (FRAME_WINDOW_P (it->f) ? (it->current_x >= it->last_visible_x) : (it->current_x > it->last_visible_x))) @@ -18579,7 +18715,7 @@ { struct glyph *glyph = row->glyphs[TEXT_AREA] + n_glyphs_before + i; - if (!it->truncate_lines_p + if (it->line_wrap != TRUNCATE && x + glyph->pixel_width > max_x) { /* End of continued line or max_x reached. */ @@ -18635,7 +18771,7 @@ set_iterator_to_next (it, 1); /* Stop if truncating at the right edge. */ - if (it->truncate_lines_p + if (it->line_wrap == TRUNCATE && it->current_x >= it->last_visible_x) { /* Add truncation mark, but don't do it if the line is @@ -20583,7 +20719,7 @@ else ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font); - if (width > 0 && !it->truncate_lines_p + if (width > 0 && it->line_wrap != TRUNCATE && it->current_x + width > it->last_visible_x) width = it->last_visible_x - it->current_x - 1; @@ -24538,11 +24674,18 @@ DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: /* Don't ask. */); #endif - DEFVAR_BOOL ("truncate-partial-width-windows", - &truncate_partial_width_windows, - doc: /* *Non-nil means truncate lines in all windows less than full frame wide. + DEFVAR_LISP ("truncate-partial-width-windows", + &Vtruncate_partial_width_windows, + doc: /* Non-nil means truncate lines in windows with less than the frame width. +For an integer value, truncate lines in each window with less than the +full frame width, provided the window width is less than that integer; +otherwise, respect the value of `truncate-lines'. + +For any other non-nil value, truncate lines in all windows with +less than the full frame width. + Nil means to respect the value of `truncate-lines'. */); - truncate_partial_width_windows = 1; + Vtruncate_partial_width_windows = make_number (30); DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video, doc: /* When nil, display the mode-line/header-line/menu-bar in the default face.