Note that the display optimizations in these cases may cause the
buffer to be occasionally mis-fontified.
+The new function 'long-line-optimizations-p' returns non-nil when
+these optimizations are in effect in the current buffer.
+
+++
** New command to change the font size globally.
To increase the font size, type 'C-x C-M-+' or 'C-x C-M-='; to
;; But don't vscroll in a keyboard macro.
(not defining-kbd-macro)
(not executing-kbd-macro)
+ ;; Lines are not truncated...
+ (not
+ (and
+ (or truncate-lines
+ (and (integerp truncate-partial-width-windows)
+ (< (window-total-width)
+ truncate-partial-width-windows))
+ (and truncate-partial-width-windows
+ (not (integerp truncate-partial-width-windows))
+ (not (window-full-width-p))))
+ ;; ...or if lines are truncated, this buffer
+ ;; doesn't have very long lines.
+ (long-line-optimizations-p)))
(line-move-partial arg noerror))
(set-window-vscroll nil 0 t)
(if (and line-move-visual
;; Display-based column are incompatible with goal-column.
(not goal-column)
+ ;; Lines aren't truncated.
+ (not
+ (or truncate-lines
+ (and (integerp truncate-partial-width-windows)
+ (< (window-width)
+ truncate-partial-width-windows))
+ (and truncate-partial-width-windows
+ (not (integerp truncate-partial-width-windows))
+ (not (window-full-width-p)))))
;; When the text in the window is scrolled to the left,
;; display-based motion doesn't make sense (because each
;; logical line occupies exactly one screen line).
(line-move (1- arg) t)))
;; Move to beginning-of-line, ignoring fields and invisible text.
- (skip-chars-backward "^\n")
- (while (and (not (bobp)) (invisible-p (1- (point))))
- (goto-char (previous-char-property-change (point)))
- (skip-chars-backward "^\n"))
+ (let ((inhibit-field-text-motion t))
+ (goto-char (line-beginning-position))
+ (while (and (not (bobp)) (invisible-p (1- (point))))
+ (goto-char (previous-char-property-change (point)))
+ (goto-char (line-beginning-position))))
;; Now find first visible char in the line.
(while (and (< (point) orig) (invisible-p (point)))
will have a variable width).
Ignores finite width of frame, which means that this function may return
values greater than (frame-width).
-In a buffer with very long lines, the value can be zero, because calculating
-the exact number is very expensive.
+In a buffer with very long lines, the value will be an approximation,
+because calculating the exact number is very expensive.
Whether the line is visible (if `selective-display' is t) has no effect;
however, ^M is treated as end of line when `selective-display' is t.
Text that has an invisible property is considered as having width 0, unless
{
Lisp_Object temp;
- if (current_buffer->long_line_optimizations_p)
- return make_fixnum (0);
XSETFASTINT (temp, current_column ());
return temp;
}
&& MODIFF == last_known_column_modified)
return last_known_column;
+ ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
+ NULL, NULL, 1);
+
+ /* Avoid becoming abysmally slow for very long lines. */
+ if (current_buffer->long_line_optimizations_p
+ && !NILP (Vlong_line_threshold)
+ && PT - line_beg > XFIXNUM (Vlong_line_threshold))
+ return PT - line_beg; /* this is an approximation! */
/* If the buffer has overlays, text properties,
or multibyte characters, use a more general algorithm. */
if (buffer_intervals (current_buffer)
ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
- next_boundary = scan;
- prev_pos = scan;
- prev_bpos = scan_byte;
window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
w = ! NILP (window) ? XWINDOW (window) : NULL;
+ if (current_buffer->long_line_optimizations_p)
+ {
+ bool lines_truncated = false;
+
+ if (!NILP (BVAR (current_buffer, truncate_lines)))
+ lines_truncated = true;
+ else if (w && FIXNUMP (Vtruncate_partial_width_windows))
+ lines_truncated =
+ w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
+ else if (w && !NILP (Vtruncate_partial_width_windows))
+ lines_truncated =
+ w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w)));
+ /* Special optimization for buffers with long and truncated
+ lines: assumes that each character is a single column. */
+ if (lines_truncated)
+ {
+ ptrdiff_t bolpos = scan;
+ /* The newline which ends this line or ZV. */
+ ptrdiff_t eolpos =
+ find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
+
+ scan = bolpos + goal;
+ if (scan > end)
+ scan = end;
+ if (scan > eolpos)
+ scan = (eolpos == ZV ? ZV : eolpos - 1);
+ col = scan - bolpos;
+ if (col > large_hscroll_threshold)
+ {
+ prev_col = col - 1;
+ prev_pos = scan - 1;
+ prev_bpos = CHAR_TO_BYTE (scan);
+ goto endloop;
+ }
+ /* Restore the values we've overwritten above. */
+ scan = bolpos;
+ col = 0;
+ }
+ }
+ next_boundary = scan;
+ prev_pos = scan;
+ prev_bpos = scan_byte;
+
memset (&cmp_it, 0, sizeof cmp_it);
cmp_it.id = -1;
composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
in case scroll_margin is buffer-local. */
this_scroll_margin = window_scroll_margin (w, MARGIN_IN_LINES);
- /* Don't use redisplay code for initial frames, as the necessary
- data structures might not be set up yet then. */
- if (!FRAME_INITIAL_P (XFRAME (w->frame)))
+ /* Don't use the display code for initial frames, as the necessary
+ data structures might not be set up yet then. Also don't use it
+ for buffers with very long lines, as it tremdously slows down
+ redisplay, especially when lines are truncated. */
+ if (!FRAME_INITIAL_P (XFRAME (w->frame))
+ && !current_buffer->long_line_optimizations_p)
{
specpdl_ref count = SPECPDL_INDEX ();
{
return (w->column_number_displayed != -1
&& !(PT == w->last_point && !window_outdated (w))
- && (!current_buffer->long_line_optimizations_p
- && w->column_number_displayed != current_column ()));
+ && (w->column_number_displayed != current_column ()));
}
/* True if window start of W is frozen and may not be changed during
return true;
}
+DEFUN ("long-line-optimizations-p", Flong_line_optimizations_p, Slong_line_optimizations_p,
+ 0, 0, 0,
+ doc: /* Return non-nil if long-line optimizations are in effect in current buffer.
+See `long-line-threshold' and `large-hscroll-threshold' for what these
+optimizations mean and when they are in effect. */)
+ (void)
+{
+ return current_buffer->long_line_optimizations_p ? Qt : Qnil;
+}
+
/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P means only
selected_window is redisplayed.
ptrdiff_t it_charpos;
w->optional_new_start = false;
- start_display (&it, w, startp);
- move_it_to (&it, PT, 0, it.last_visible_y, -1,
- MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
- /* Record IT's position now, since line_bottom_y might change
- that. */
- it_charpos = IT_CHARPOS (it);
- /* Make sure we set the force_start flag only if the cursor row
- will be fully visible. Otherwise, the code under force_start
- label below will try to move point back into view, which is
- not what the code which sets optional_new_start wants. */
- if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
- && !w->force_start)
- {
- if (it_charpos == PT)
- w->force_start = true;
- /* IT may overshoot PT if text at PT is invisible. */
- else if (it_charpos > PT && CHARPOS (startp) <= PT)
- w->force_start = true;
+ if (!w->force_start)
+ {
+ start_display (&it, w, startp);
+ move_it_to (&it, PT, 0, it.last_visible_y, -1,
+ MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+ /* Record IT's position now, since line_bottom_y might
+ change that. */
+ it_charpos = IT_CHARPOS (it);
+ /* Make sure we set the force_start flag only if the cursor
+ row will be fully visible. Otherwise, the code under
+ force_start label below will try to move point back into
+ view, which is not what the code which sets
+ optional_new_start wants. */
+ if (it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
+ {
+ if (it_charpos == PT)
+ w->force_start = true;
+ /* IT may overshoot PT if text at PT is invisible. */
+ else if (it_charpos > PT && CHARPOS (startp) <= PT)
+ w->force_start = true;
#ifdef GLYPH_DEBUG
- if (w->force_start)
- {
- if (window_frozen_p (w))
- debug_method_add (w, "set force_start from frozen window start");
- else
- debug_method_add (w, "set force_start from optional_new_start");
- }
+ if (w->force_start)
+ {
+ if (window_frozen_p (w))
+ debug_method_add (w, "set force_start from frozen window start");
+ else
+ debug_method_add (w, "set force_start from optional_new_start");
+ }
#endif
+ }
}
}
|| w->base_line_pos > 0
/* Column number is displayed and different from the one displayed. */
|| (w->column_number_displayed != -1
- && !current_buffer->long_line_optimizations_p
&& (w->column_number_displayed != current_column ())))
/* This means that the window has a mode line. */
&& (window_wants_mode_line (w)
even crash emacs.) */
if (mode_line_target == MODE_LINE_TITLE)
return "";
- else if (b->long_line_optimizations_p)
- {
- char *p = decode_mode_spec_buf;
- int pad = width - 2;
- while (pad-- > 0)
- *p++ = ' ';
- *p++ = '?';
- *p++ = '?';
- *p = '\0';
- return decode_mode_spec_buf;
- }
else
{
ptrdiff_t col = current_column ();
defsubr (&Sbidi_find_overridden_directionality);
defsubr (&Sdisplay__line_is_continued_p);
defsubr (&Sget_display_property);
+ defsubr (&Slong_line_optimizations_p);
DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");