Merge branch 'feature/fix-the-long-lines-display-bug'
This commit is contained in:
commit
616da8fa8e
16 changed files with 167 additions and 112 deletions
|
@ -1190,7 +1190,6 @@ Dealing with Emacs Trouble
|
|||
* Crashing:: What Emacs does when it crashes.
|
||||
* After a Crash:: Recovering editing in an Emacs session that crashed.
|
||||
* Emergency Escape:: What to do if Emacs stops responding.
|
||||
* Long Lines:: Mitigating slowness due to extremely long lines.
|
||||
* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete.
|
||||
|
||||
Reporting Bugs
|
||||
|
|
|
@ -158,7 +158,6 @@ Emacs.
|
|||
* Crashing:: What Emacs does when it crashes.
|
||||
* After a Crash:: Recovering editing in an Emacs session that crashed.
|
||||
* Emergency Escape:: What to do if Emacs stops responding.
|
||||
* Long Lines:: Mitigating slowness due to extremely long lines.
|
||||
* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete.
|
||||
@end menu
|
||||
|
||||
|
@ -433,64 +432,6 @@ program.
|
|||
emergency escape---but there are cases where it won't work, when a
|
||||
system call hangs or when Emacs is stuck in a tight loop in C code.
|
||||
|
||||
@node Long Lines
|
||||
@subsection Long Lines
|
||||
@cindex long lines
|
||||
|
||||
For a variety of reasons (some of which are fundamental to the Emacs
|
||||
redisplay code and the complex range of possibilities it handles;
|
||||
others of which are due to modes and features which do not scale well
|
||||
in unusual circumstances), Emacs can perform poorly when extremely
|
||||
long lines are present (where ``extremely long'' usually means at
|
||||
least many thousands of characters).
|
||||
|
||||
@cindex @code{so-long} mode
|
||||
@findex global-so-long-mode
|
||||
@vindex so-long-action
|
||||
A particular problem is that Emacs may ``hang'' for a long time at
|
||||
the point of visiting a file with extremely long lines. This can be
|
||||
mitigated by enabling the @file{so-long} library, which detects when a
|
||||
visited file contains abnormally long lines, and takes steps to
|
||||
disable features which are liable to cause slowness in that situation.
|
||||
To enable this library, type @kbd{M-x global-so-long-mode @key{RET}},
|
||||
or turn on the @code{global-so-long-mode} in your init file
|
||||
(@pxref{Init File}), or customize the @code{global-so-long-mode}
|
||||
option. You can tailor this mode's operation by customizing the
|
||||
variable @code{so-long-action}.
|
||||
|
||||
The @file{so-long} library can also significantly improve
|
||||
performance when moving and editing in a buffer with long lines.
|
||||
Performance is still likely to degrade as you get deeper into the long
|
||||
lines, but the improvements from using this library can nevertheless
|
||||
be substantial.
|
||||
|
||||
@findex so-long-commentary
|
||||
Use @kbd{M-x so-long-commentary} to view the documentation for this
|
||||
library and learn more about how to enable and configure it.
|
||||
|
||||
@vindex max-redisplay-ticks
|
||||
If even @code{so-long-mode} doesn't help making Emacs responsive
|
||||
enough, or if you'd rather not disable the display-related features
|
||||
that @code{so-long-mode} turns off, you can instead customize the
|
||||
variable @code{max-redisplay-ticks} to a non-zero value. Then Emacs
|
||||
will abort redisplay of a window and commands, like @kbd{C-n} and
|
||||
@kbd{M-v}, which use the display code to do their job, if processing a
|
||||
window needs more low-level display operations than the value of this
|
||||
variable. The display of the offending window will then remain
|
||||
outdated, and possibly incomplete, on the screen, but Emacs should
|
||||
otherwise be responsive, and you could then switch to another buffer,
|
||||
or kill the problematic buffer, or turn on @code{so-long-mode} or
|
||||
@code{so-long-minor-mode} in that buffer. When the display of a
|
||||
window is aborted due to this reason, the buffer shown in that window
|
||||
will not have any of its windows redisplayed until the buffer is
|
||||
modified or until you type @kbd{C-l} (@pxref{Recentering}) in one of
|
||||
that buffer's windows.
|
||||
|
||||
If you decide to customize this variable to a non-zero value, we
|
||||
recommend to use a value between 100,000 and 1,000,000, depending on
|
||||
your patience and the speed of your system. The default value is
|
||||
zero, which disables this feature.
|
||||
|
||||
@node DEL Does Not Delete
|
||||
@subsection If @key{DEL} Fails to Delete
|
||||
@cindex @key{DEL} vs @key{BACKSPACE}
|
||||
|
|
24
etc/NEWS
24
etc/NEWS
|
@ -334,7 +334,16 @@ Use something like 'M-x shell RET ssh <host> RET' instead.
|
|||
* Changes in Emacs 29.1
|
||||
|
||||
---
|
||||
** 'longlines-mode' is no longer obsolete.
|
||||
** Emacs is now capable of editing files with arbitrarily long lines.
|
||||
The display of long lines has been optimized, and Emacs no longer
|
||||
chokes when a buffer on display contains long lines. If you still
|
||||
experience slowdowns while editing files with long lines, this is
|
||||
either due to font locking, which you can turn off with M-x
|
||||
font-lock-mode or C-u C-x x f, or to the current major mode or one of
|
||||
the enabled minor modes, in which case you should open the the file
|
||||
with M-x find-file-literally instead of C-x C-f. The variable
|
||||
'long-line-threshold' controls whether and when these display
|
||||
optimizations are used.
|
||||
|
||||
+++
|
||||
** New command to change the font size globally.
|
||||
|
@ -356,10 +365,10 @@ Get the parent directory of a file.
|
|||
This variable is used by some operations (mostly syntax-propertization
|
||||
and font-locking) to treat lines longer than this variable as if they
|
||||
were made up of various smaller lines. This can help reduce the
|
||||
pathological slowdowns seen in buffers made of a single long line, but
|
||||
can also cause misbehavior in the presence of such long lines (tho
|
||||
most of that misbehavior should usually be limited to mis-highlighting).
|
||||
You can recover the previous behavior with:
|
||||
slowdowns seen in buffers made of a single long line, but can also
|
||||
cause misbehavior in the presence of such long lines (tho most of that
|
||||
misbehavior should usually be limited to mis-highlighting). You can
|
||||
recover the previous behavior with:
|
||||
|
||||
(setq syntax-wholeline-max most-positive-fixnum)
|
||||
|
||||
|
@ -471,11 +480,6 @@ including those typed in response to passwords prompt (this was the
|
|||
previous behavior). The default is nil, which inhibits recording of
|
||||
passwords.
|
||||
|
||||
+++
|
||||
** New user option 'longlines-break-chars'.
|
||||
This is a string containing chars that could be used as break point in
|
||||
longlines mode.
|
||||
|
||||
+++
|
||||
** New function 'command-query'.
|
||||
This function makes its argument command prompt the user for
|
||||
|
|
|
@ -568,12 +568,6 @@ This can happen with CVS versions 1.12.8 and 1.12.9. Upgrade to CVS
|
|||
|
||||
** Miscellaneous problems
|
||||
|
||||
*** Editing files with very long lines is slow.
|
||||
|
||||
For example, simply moving through a file that contains hundreds of
|
||||
thousands of characters per line is slow, and consumes a lot of CPU.
|
||||
This is a known limitation of Emacs with no solution at this time.
|
||||
|
||||
*** Display artifacts on GUI frames on X-based systems.
|
||||
|
||||
This is known to be caused by using double-buffering (which is enabled
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
;; Alex Schroeder <alex@gnu.org>
|
||||
;; Chong Yidong <cyd@stupidchicken.com>
|
||||
;; Maintainer: emacs-devel@gnu.org
|
||||
;; Obsolete-since: 24.4
|
||||
;; Keywords: convenience, wp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
26
src/buffer.c
26
src/buffer.c
|
@ -985,6 +985,7 @@ reset_buffer (register struct buffer *b)
|
|||
/* It is more conservative to start out "changed" than "unchanged". */
|
||||
b->clip_changed = 0;
|
||||
b->prevent_redisplay_optimizations_p = 1;
|
||||
b->long_line_optimizations_p = 0;
|
||||
bset_backed_up (b, Qnil);
|
||||
bset_local_minor_modes (b, Qnil);
|
||||
BUF_AUTOSAVE_MODIFF (b) = 0;
|
||||
|
@ -1501,7 +1502,7 @@ state of the current buffer. Use with care. */)
|
|||
decrease SAVE_MODIFF and auto_save_modified or increase
|
||||
MODIFF. */
|
||||
if (SAVE_MODIFF >= MODIFF)
|
||||
SAVE_MODIFF = modiff_incr (&MODIFF);
|
||||
SAVE_MODIFF = modiff_incr (&MODIFF, 1);
|
||||
if (EQ (flag, Qautosaved))
|
||||
BUF_AUTOSAVE_MODIFF (b) = MODIFF;
|
||||
}
|
||||
|
@ -2446,6 +2447,7 @@ results, see Info node `(elisp)Swapping Text'. */)
|
|||
swapfield (bidi_paragraph_cache, struct region_cache *);
|
||||
current_buffer->prevent_redisplay_optimizations_p = 1;
|
||||
other_buffer->prevent_redisplay_optimizations_p = 1;
|
||||
swapfield (long_line_optimizations_p, bool_bf);
|
||||
swapfield (overlays_before, struct Lisp_Overlay *);
|
||||
swapfield (overlays_after, struct Lisp_Overlay *);
|
||||
swapfield (overlay_center, ptrdiff_t);
|
||||
|
@ -2465,12 +2467,12 @@ results, see Info node `(elisp)Swapping Text'. */)
|
|||
bset_point_before_scroll (current_buffer, Qnil);
|
||||
bset_point_before_scroll (other_buffer, Qnil);
|
||||
|
||||
modiff_incr (¤t_buffer->text->modiff);
|
||||
modiff_incr (&other_buffer->text->modiff);
|
||||
modiff_incr (¤t_buffer->text->chars_modiff);
|
||||
modiff_incr (&other_buffer->text->chars_modiff);
|
||||
modiff_incr (¤t_buffer->text->overlay_modiff);
|
||||
modiff_incr (&other_buffer->text->overlay_modiff);
|
||||
modiff_incr (¤t_buffer->text->modiff, 1);
|
||||
modiff_incr (&other_buffer->text->modiff, 1);
|
||||
modiff_incr (¤t_buffer->text->chars_modiff, 1);
|
||||
modiff_incr (&other_buffer->text->chars_modiff, 1);
|
||||
modiff_incr (¤t_buffer->text->overlay_modiff, 1);
|
||||
modiff_incr (&other_buffer->text->overlay_modiff, 1);
|
||||
current_buffer->text->beg_unchanged = current_buffer->text->gpt;
|
||||
current_buffer->text->end_unchanged = current_buffer->text->gpt;
|
||||
other_buffer->text->beg_unchanged = other_buffer->text->gpt;
|
||||
|
@ -4009,7 +4011,7 @@ modify_overlay (struct buffer *buf, ptrdiff_t start, ptrdiff_t end)
|
|||
|
||||
bset_redisplay (buf);
|
||||
|
||||
modiff_incr (&BUF_OVERLAY_MODIFF (buf));
|
||||
modiff_incr (&BUF_OVERLAY_MODIFF (buf), 1);
|
||||
}
|
||||
|
||||
/* Remove OVERLAY from LIST. */
|
||||
|
@ -6427,6 +6429,14 @@ Since `clone-indirect-buffer' calls `make-indirect-buffer', this hook
|
|||
will run for `clone-indirect-buffer' calls as well. */);
|
||||
Vclone_indirect_buffer_hook = Qnil;
|
||||
|
||||
DEFVAR_LISP ("long-line-threshold", Vlong_line_threshold,
|
||||
doc: /* Line length above which specific display optimizations are used.
|
||||
Display optimizations for long lines will automatically be enabled in
|
||||
buffers which contain one or more lines whose length is above that
|
||||
threshold.
|
||||
When nil, these display optimizations are disabled. */);
|
||||
XSETFASTINT (Vlong_line_threshold, 10000);
|
||||
|
||||
defsubr (&Sbuffer_live_p);
|
||||
defsubr (&Sbuffer_list);
|
||||
defsubr (&Sget_buffer);
|
||||
|
|
11
src/buffer.h
11
src/buffer.h
|
@ -237,9 +237,10 @@ struct buffer_text
|
|||
ptrdiff_t z_byte; /* Byte pos of end of buffer. */
|
||||
ptrdiff_t gap_size; /* Size of buffer's gap. */
|
||||
modiff_count modiff; /* This counts buffer-modification events
|
||||
for this buffer. It is incremented for
|
||||
each such event, and never otherwise
|
||||
changed. */
|
||||
for this buffer. It is increased
|
||||
logarithmically to the extent of the
|
||||
modification for each such event,
|
||||
and never otherwise changed. */
|
||||
modiff_count chars_modiff; /* This is modified with character change
|
||||
events for this buffer. It is set to
|
||||
modiff for each such event, and never
|
||||
|
@ -681,6 +682,10 @@ struct buffer
|
|||
defined, as well as by with-temp-buffer, for example. */
|
||||
bool_bf inhibit_buffer_hooks : 1;
|
||||
|
||||
/* Non-zero when the buffer contains long lines and specific
|
||||
display optimizations must be used. */
|
||||
bool_bf long_line_optimizations_p : 1;
|
||||
|
||||
/* List of overlays that end at or before the current center,
|
||||
in order of end-position. */
|
||||
struct Lisp_Overlay *overlays_before;
|
||||
|
|
|
@ -1580,6 +1580,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
|
|||
Lisp_Object window;
|
||||
struct window *w;
|
||||
bool need_adjustment = 0;
|
||||
ptrdiff_t narrowed_begv;
|
||||
|
||||
window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
|
||||
if (NILP (window))
|
||||
|
@ -1596,6 +1597,11 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
|
|||
}
|
||||
else
|
||||
head = backlim;
|
||||
/* In buffers with very long lines, this function becomes very
|
||||
slow. Pretend that the buffer is narrowed to make it fast. */
|
||||
narrowed_begv = get_narrowed_begv (w);
|
||||
if (narrowed_begv && pos > narrowed_begv)
|
||||
head = narrowed_begv;
|
||||
tail = ZV;
|
||||
stop = GPT;
|
||||
cur.pos_byte = CHAR_TO_BYTE (cur.pos);
|
||||
|
|
|
@ -2332,6 +2332,10 @@ struct it
|
|||
with which display_string was called. */
|
||||
ptrdiff_t end_charpos;
|
||||
|
||||
/* Alternate begin position of the buffer that may be used to
|
||||
optimize display (see the SET_WITH_NARROWED_BEGV macro). */
|
||||
ptrdiff_t narrowed_begv;
|
||||
|
||||
/* C string to iterate over. Non-null means get characters from
|
||||
this string, otherwise characters are read from current_buffer
|
||||
or it->string. */
|
||||
|
@ -3396,6 +3400,7 @@ void mark_window_display_accurate (Lisp_Object, bool);
|
|||
void redisplay_preserve_echo_area (int);
|
||||
void init_iterator (struct it *, struct window *, ptrdiff_t,
|
||||
ptrdiff_t, struct glyph_row *, enum face_id);
|
||||
ptrdiff_t get_narrowed_begv (struct window *w);
|
||||
void init_iterator_to_row_start (struct it *, struct window *,
|
||||
struct glyph_row *);
|
||||
void start_display (struct it *, struct window *, struct text_pos);
|
||||
|
|
18
src/insdel.c
18
src/insdel.c
|
@ -909,7 +909,7 @@ insert_1_both (const char *string,
|
|||
the insertion. This, together with recording the insertion,
|
||||
will add up to the right stuff in the undo list. */
|
||||
record_insert (PT, nchars);
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
memcpy (GPT_ADDR, string, nbytes);
|
||||
|
@ -1037,7 +1037,7 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
|
|||
#endif
|
||||
|
||||
record_insert (PT, nchars);
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
GAP_SIZE -= outgoing_nbytes;
|
||||
|
@ -1122,7 +1122,7 @@ insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
|
|||
of this dance. */
|
||||
invalidate_buffer_caches (current_buffer, GPT, GPT);
|
||||
record_insert (GPT, nchars);
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
insert_from_gap_1 (nchars, nbytes, text_at_gap_tail);
|
||||
|
@ -1251,7 +1251,7 @@ insert_from_buffer_1 (struct buffer *buf,
|
|||
#endif
|
||||
|
||||
record_insert (PT, nchars);
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
GAP_SIZE -= outgoing_nbytes;
|
||||
|
@ -1352,7 +1352,7 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
|
|||
|
||||
if (len == 0)
|
||||
evaporate_overlays (from);
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars_del + len);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
}
|
||||
|
||||
|
@ -1547,7 +1547,7 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
|
|||
|
||||
check_markers ();
|
||||
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars_del + inschars);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
if (adjust_match_data)
|
||||
|
@ -1681,7 +1681,7 @@ replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
|
|||
|
||||
check_markers ();
|
||||
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars_del + inschars);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
}
|
||||
|
||||
|
@ -1856,7 +1856,7 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
|
|||
at the end of the text before the gap. */
|
||||
adjust_markers_for_delete (from, from_byte, to, to_byte);
|
||||
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, nchars_del);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
/* Relocate point as if it were a marker. */
|
||||
|
@ -1910,7 +1910,7 @@ modify_text (ptrdiff_t start, ptrdiff_t end)
|
|||
BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end);
|
||||
if (MODIFF <= SAVE_MODIFF)
|
||||
record_first_change ();
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, end - start);
|
||||
CHARS_MODIFF = MODIFF;
|
||||
|
||||
bset_point_before_scroll (current_buffer, Qnil);
|
||||
|
|
12
src/lisp.h
12
src/lisp.h
|
@ -3911,10 +3911,14 @@ integer_to_uintmax (Lisp_Object num, uintmax_t *n)
|
|||
typedef intmax_t modiff_count;
|
||||
|
||||
INLINE modiff_count
|
||||
modiff_incr (modiff_count *a)
|
||||
modiff_incr (modiff_count *a, ptrdiff_t len)
|
||||
{
|
||||
modiff_count a0 = *a;
|
||||
bool modiff_overflow = INT_ADD_WRAPV (a0, 1, a);
|
||||
modiff_count a0 = *a; int incr = len ? 1 : 0;
|
||||
/* Increase the counter more for a large modification and less for a
|
||||
small modification. Increase it logarithmically to avoid
|
||||
increasing it too much. */
|
||||
while (len >>= 1) incr++;
|
||||
bool modiff_overflow = INT_ADD_WRAPV (a0, incr, a);
|
||||
eassert (!modiff_overflow && *a >> 30 >> 30 == 0);
|
||||
return a0;
|
||||
}
|
||||
|
@ -4762,6 +4766,8 @@ extern ptrdiff_t fast_c_string_match_ignore_case (Lisp_Object, const char *,
|
|||
ptrdiff_t);
|
||||
extern ptrdiff_t fast_looking_at (Lisp_Object, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, ptrdiff_t, Lisp_Object);
|
||||
extern ptrdiff_t find_newline1 (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
|
||||
extern ptrdiff_t find_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
ptrdiff_t, ptrdiff_t *, ptrdiff_t *, bool);
|
||||
extern void scan_newline (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t,
|
||||
|
|
|
@ -3192,7 +3192,7 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0,
|
|||
}
|
||||
|
||||
/* Like find_newline, but doesn't use the cache, and only searches forward. */
|
||||
static ptrdiff_t
|
||||
ptrdiff_t
|
||||
find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end,
|
||||
ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *counted,
|
||||
ptrdiff_t *bytepos, bool allow_quit)
|
||||
|
|
|
@ -88,7 +88,7 @@ modify_text_properties (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
|
|||
BUF_COMPUTE_UNCHANGED (buf, b - 1, e);
|
||||
if (MODIFF <= SAVE_MODIFF)
|
||||
record_first_change ();
|
||||
modiff_incr (&MODIFF);
|
||||
modiff_incr (&MODIFF, 1);
|
||||
|
||||
bset_point_before_scroll (current_buffer, Qnil);
|
||||
|
||||
|
|
|
@ -1028,7 +1028,7 @@ window_body_unit_from_symbol (Lisp_Object unit)
|
|||
/* Return the number of lines/pixels of W's body. Don't count any mode
|
||||
or header line or horizontal divider of W. Rounds down to nearest
|
||||
integer when not working pixelwise. */
|
||||
static int
|
||||
int
|
||||
window_body_height (struct window *w, enum window_body_unit pixelwise)
|
||||
{
|
||||
int height = (w->pixel_height
|
||||
|
|
|
@ -1193,6 +1193,7 @@ enum window_body_unit
|
|||
WINDOW_BODY_IN_REMAPPED_CHARS
|
||||
};
|
||||
extern int window_body_width (struct window *w, enum window_body_unit);
|
||||
extern int window_body_height (struct window *w, enum window_body_unit);
|
||||
enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
|
||||
extern int window_scroll_margin (struct window *, enum margin_unit);
|
||||
extern void temp_output_buffer_show (Lisp_Object);
|
||||
|
|
103
src/xdisp.c
103
src/xdisp.c
|
@ -3425,6 +3425,9 @@ init_iterator (struct it *it, struct window *w,
|
|||
}
|
||||
}
|
||||
|
||||
if (current_buffer->long_line_optimizations_p)
|
||||
it->narrowed_begv = get_narrowed_begv (w);
|
||||
|
||||
/* If a buffer position was specified, set the iterator there,
|
||||
getting overlays and face properties from that position. */
|
||||
if (charpos >= BUF_BEG (current_buffer))
|
||||
|
@ -3491,6 +3494,45 @@ init_iterator (struct it *it, struct window *w,
|
|||
CHECK_IT (it);
|
||||
}
|
||||
|
||||
/* Compute a suitable alternate value for BEGV that may be used
|
||||
temporarily to optimize display if the buffer in window W contains
|
||||
long lines. */
|
||||
|
||||
ptrdiff_t
|
||||
get_narrowed_begv (struct window *w)
|
||||
{
|
||||
int len, fact; ptrdiff_t begv;
|
||||
/* In a character-only terminal, only one font size is used, so we
|
||||
can use a smaller factor. */
|
||||
fact = EQ (Fterminal_live_p (Qnil), Qt) ? 2 : 3;
|
||||
len = fact * (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
|
||||
window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS));
|
||||
begv = max ((window_point (w) / len - 1) * len, BEGV);
|
||||
return begv == BEGV ? 0 : begv;
|
||||
}
|
||||
|
||||
static void
|
||||
unwind_narrowed_begv (Lisp_Object point_min)
|
||||
{
|
||||
SET_BUF_BEGV (current_buffer, XFIXNUM (point_min));
|
||||
}
|
||||
|
||||
/* Set DST to EXPR. When IT indicates that BEGV should temporarily be
|
||||
updated to optimize display, evaluate EXPR with an updated BEGV. */
|
||||
|
||||
#define SET_WITH_NARROWED_BEGV(IT,DST,EXPR) \
|
||||
do { \
|
||||
if (IT->narrowed_begv) \
|
||||
{ \
|
||||
specpdl_ref count = SPECPDL_INDEX (); \
|
||||
record_unwind_protect (unwind_narrowed_begv, Fpoint_min ()); \
|
||||
SET_BUF_BEGV (current_buffer, IT->narrowed_begv); \
|
||||
DST = EXPR; \
|
||||
unbind_to (count, Qnil); \
|
||||
} \
|
||||
else \
|
||||
DST = EXPR; \
|
||||
} while (0)
|
||||
|
||||
/* Initialize IT for the display of window W with window start POS. */
|
||||
|
||||
|
@ -6992,7 +7034,8 @@ back_to_previous_line_start (struct it *it)
|
|||
ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
|
||||
|
||||
dec_both (&cp, &bp);
|
||||
IT_CHARPOS (*it) = find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it));
|
||||
SET_WITH_NARROWED_BEGV (it, IT_CHARPOS (*it),
|
||||
find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -7210,7 +7253,8 @@ back_to_previous_visible_line_start (struct it *it)
|
|||
it->continuation_lines_width = 0;
|
||||
|
||||
eassert (IT_CHARPOS (*it) >= BEGV);
|
||||
eassert (IT_CHARPOS (*it) == BEGV
|
||||
eassert (it->narrowed_begv > BEGV
|
||||
|| IT_CHARPOS (*it) == BEGV
|
||||
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
|
||||
CHECK_IT (it);
|
||||
}
|
||||
|
@ -8623,7 +8667,12 @@ get_visually_first_element (struct it *it)
|
|||
{
|
||||
bool string_p = STRINGP (it->string) || it->s;
|
||||
ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV);
|
||||
ptrdiff_t bob = (string_p ? 0 : BEGV);
|
||||
ptrdiff_t bob;
|
||||
ptrdiff_t obegv = BEGV;
|
||||
|
||||
SET_WITH_NARROWED_BEGV (it, bob,
|
||||
string_p ? 0 :
|
||||
IT_BYTEPOS (*it) < BEGV ? obegv : BEGV);
|
||||
|
||||
if (STRINGP (it->string))
|
||||
{
|
||||
|
@ -8663,9 +8712,10 @@ get_visually_first_element (struct it *it)
|
|||
if (string_p)
|
||||
it->bidi_it.charpos = it->bidi_it.bytepos = 0;
|
||||
else
|
||||
it->bidi_it.charpos = find_newline_no_quit (IT_CHARPOS (*it),
|
||||
IT_BYTEPOS (*it), -1,
|
||||
&it->bidi_it.bytepos);
|
||||
SET_WITH_NARROWED_BEGV (it, it->bidi_it.charpos,
|
||||
find_newline_no_quit (IT_CHARPOS (*it),
|
||||
IT_BYTEPOS (*it), -1,
|
||||
&it->bidi_it.bytepos));
|
||||
bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
|
||||
do
|
||||
{
|
||||
|
@ -10583,7 +10633,8 @@ move_it_vertically_backward (struct it *it, int dy)
|
|||
ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
|
||||
|
||||
dec_both (&cp, &bp);
|
||||
cp = find_newline_no_quit (cp, bp, -1, NULL);
|
||||
SET_WITH_NARROWED_BEGV (it, cp,
|
||||
find_newline_no_quit (cp, bp, -1, NULL));
|
||||
move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
|
||||
}
|
||||
bidi_unshelve_cache (it3data, true);
|
||||
|
@ -18879,11 +18930,25 @@ set_vertical_scroll_bar (struct window *w)
|
|||
&& NILP (echo_area_buffer[0])))
|
||||
{
|
||||
struct buffer *buf = XBUFFER (w->contents);
|
||||
ptrdiff_t window_end_pos = w->window_end_pos;
|
||||
|
||||
/* If w->window_end_pos cannot be trusted, recompute it "the
|
||||
hard way". */
|
||||
if (!w->window_end_valid)
|
||||
{
|
||||
struct it it;
|
||||
struct text_pos start_pos;
|
||||
|
||||
SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
|
||||
start_display (&it, w, start_pos);
|
||||
move_it_to (&it, -1, it.last_visible_x, window_box_height (w), -1,
|
||||
MOVE_TO_X | MOVE_TO_Y);
|
||||
window_end_pos = BUF_Z (buf) - IT_CHARPOS (it);
|
||||
}
|
||||
|
||||
whole = BUF_ZV (buf) - BUF_BEGV (buf);
|
||||
start = marker_position (w->start) - BUF_BEGV (buf);
|
||||
/* I don't think this is guaranteed to be right. For the
|
||||
moment, we'll pretend it is. */
|
||||
end = BUF_Z (buf) - w->window_end_pos - BUF_BEGV (buf);
|
||||
end = BUF_Z (buf) - window_end_pos - BUF_BEGV (buf);
|
||||
|
||||
if (end < start)
|
||||
end = start;
|
||||
|
@ -19232,6 +19297,24 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
|
|||
}
|
||||
}
|
||||
|
||||
/* Check whether the buffer to be displayed contains long lines. */
|
||||
if (!NILP (Vlong_line_threshold)
|
||||
&& !current_buffer->long_line_optimizations_p
|
||||
&& MODIFF - UNCHANGED_MODIFIED > 8)
|
||||
{
|
||||
ptrdiff_t cur, next, found, max = 0, threshold;
|
||||
threshold = XFIXNUM (Vlong_line_threshold);
|
||||
for (cur = 1; cur < Z; cur = next)
|
||||
{
|
||||
next = find_newline1 (cur, CHAR_TO_BYTE (cur), 0, -1, 1,
|
||||
&found, NULL, true);
|
||||
if (next - cur > max) max = next - cur;
|
||||
if (!found || max > threshold) break;
|
||||
}
|
||||
if (max > threshold)
|
||||
current_buffer->long_line_optimizations_p = true;
|
||||
}
|
||||
|
||||
/* If window-start is screwed up, choose a new one. */
|
||||
if (XMARKER (w->start)->buffer != current_buffer)
|
||||
goto recenter;
|
||||
|
|
Loading…
Add table
Reference in a new issue