Actually fix the long lines display bug (bug#56393).

* src/dispextern.h (struct it): New 'narrowed_begv' field.

* src/dispextern.h (WITH_NARROWED_BEGV): New macro.

* src/xdisp.c (get_narrowed_begv): New function.
(init_iterator): Initilize the 'narrowed_begv' field.
(back_to_previous_line_start, get_visually_first_element,
move_it_vertically_backward): Use the new macro.

* src/dispextern.h: Prototype of 'get_narrowed_begv'.

* src/window.c (window_body_height): Make it externally visible.

* src/window.h: Prototype of 'window_body_height'.

* src/composite.c (find_automatic_composition): Optimize display in buffers
with very long lines with 'get_narrowed_begv'.

* lisp/obsolete/longlines.el: Reobsolete longlines-mode.

* etc/NEWS: Announce the new minor mode, and remove the unobsoletion
indication for 'longlines-mode'.

* doc/emacs/trouble.texi (Long Lines): Remove the section.
(Lossage): Remove the entry for the Long Lines section.

* doc/emacs/emacs.texi (Top): Remove the entry for the Long Lines section.
This commit is contained in:
Gregory Heytings 2022-07-08 21:22:52 +00:00
parent 60e51595c8
commit 1792cbaddc
9 changed files with 63 additions and 77 deletions

View file

@ -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

View file

@ -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}

View file

@ -325,7 +325,14 @@ startup. Previously, these functions ignored
* Changes in Emacs 29.1
---
** 'longlines-mode' is no longer obsolete.
** Emacs is now capable of editing files with arbitarily 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 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.
+++
** New command to change the font size globally.
@ -347,10 +354,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)
@ -462,11 +469,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-breakpoint-chars'.
This is a string containing chars that could be used as breakpoint in
longlines mode.
+++
** New function 'command-query'.
This function makes its argument command prompt the user for

View file

@ -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.

View file

@ -1576,6 +1576,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))
@ -1586,6 +1587,11 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
if (NILP (string))
{
head = backlim < 0 ? BEGV : backlim, tail = ZV, stop = GPT;
/* 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 (pos > narrowed_begv)
head = narrowed_begv;
cur.pos_byte = CHAR_TO_BYTE (cur.pos);
cur.p = BYTE_POS_ADDR (cur.pos_byte);
}

View file

@ -2332,6 +2332,10 @@ struct it
with which display_string was called. */
ptrdiff_t end_charpos;
/* Alternate begin position of the buffer, which is used to optimize
display (see the WITH_NARROWED_BEGV macro below). */
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. */
@ -2813,6 +2817,18 @@ struct it
reset_box_start_end_flags ((IT)); \
} while (false)
/* Execute STATEMENT with a temporarily narrowed buffer. */
#define WITH_NARROWED_BEGV(STATEMENT) \
do { \
ptrdiff_t obegv = BEGV; \
if (it->narrowed_begv) \
SET_BUF_BEGV (current_buffer, it->narrowed_begv); \
STATEMENT; \
if (it->narrowed_begv) \
SET_BUF_BEGV (current_buffer, obegv); \
} while (0)
/* Bit-flags indicating what operation move_it_to should perform. */
enum move_operation_enum
@ -3396,6 +3412,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);

View file

@ -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

View file

@ -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);

View file

@ -3425,6 +3425,8 @@ init_iterator (struct it *it, struct window *w,
}
}
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 +3493,19 @@ init_iterator (struct it *it, struct window *w,
CHECK_IT (it);
}
/* Compute a suitable value for BEGV that can be used temporarily, to
optimize display, for the buffer in window W. */
ptrdiff_t
get_narrowed_begv (struct window *w)
{
int len, begv;
len = (1 + ((window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS)) /
10000)) * 10000;
begv = max ((PT / len - 2) * len, BEGV);
return begv == BEGV ? 0 : begv;
}
/* Initialize IT for the display of window W with window start POS. */
@ -6992,7 +7007,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));
WITH_NARROWED_BEGV (IT_CHARPOS (*it) =
find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
}
@ -8623,7 +8639,9 @@ 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;
WITH_NARROWED_BEGV (bob = (string_p ? 0 : BEGV));
if (STRINGP (it->string))
{
@ -8663,9 +8681,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);
WITH_NARROWED_BEGV (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 +10602,7 @@ 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);
WITH_NARROWED_BEGV (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);