/* 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. */
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);
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;
/* 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;
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
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))
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;
{
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) \
&& 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;
}
- /* 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. */
- 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)
+ 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. Record the x-position
+ before this display element, in case it doesn't fit on the
+ line. */
+ x = it->current_x;
+
PRODUCE_GLYPHS (it);
if (it->area != TEXT_AREA)
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. */
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)
/* 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
#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;
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
{
&& 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
{
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);
/* 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);
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. */
}
}
#endif /* HAVE_WINDOW_SYSTEM */
+ if (wrap_row_used > 0)
+ goto back_to_wrap;
}
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
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
/* 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)))
{
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. */
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
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;
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.