aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory Heytings2022-07-08 21:22:52 +0000
committerGregory Heytings2022-07-08 23:36:58 +0200
commit1792cbaddc33772c344e45fb9478bee85fee66e7 (patch)
tree6bc87aa85e8c14091ef00433a52d28b99d9d0d32
parent60e51595c8a89ffc34dbe0d36c75d1c119a7d5c5 (diff)
downloademacs-1792cbaddc33772c344e45fb9478bee85fee66e7.tar.gz
emacs-1792cbaddc33772c344e45fb9478bee85fee66e7.zip
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.
-rw-r--r--doc/emacs/emacs.texi1
-rw-r--r--doc/emacs/trouble.texi59
-rw-r--r--etc/NEWS22
-rw-r--r--lisp/obsolete/longlines.el (renamed from lisp/longlines.el)1
-rw-r--r--src/composite.c6
-rw-r--r--src/dispextern.h17
-rw-r--r--src/window.c2
-rw-r--r--src/window.h1
-rw-r--r--src/xdisp.c31
9 files changed, 63 insertions, 77 deletions
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 5e72699bbe8..b43c966f872 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -1190,7 +1190,6 @@ Dealing with Emacs Trouble
1190* Crashing:: What Emacs does when it crashes. 1190* Crashing:: What Emacs does when it crashes.
1191* After a Crash:: Recovering editing in an Emacs session that crashed. 1191* After a Crash:: Recovering editing in an Emacs session that crashed.
1192* Emergency Escape:: What to do if Emacs stops responding. 1192* Emergency Escape:: What to do if Emacs stops responding.
1193* Long Lines:: Mitigating slowness due to extremely long lines.
1194* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete. 1193* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete.
1195 1194
1196Reporting Bugs 1195Reporting Bugs
diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi
index f06b93759d8..887e5c6170f 100644
--- a/doc/emacs/trouble.texi
+++ b/doc/emacs/trouble.texi
@@ -158,7 +158,6 @@ Emacs.
158* Crashing:: What Emacs does when it crashes. 158* Crashing:: What Emacs does when it crashes.
159* After a Crash:: Recovering editing in an Emacs session that crashed. 159* After a Crash:: Recovering editing in an Emacs session that crashed.
160* Emergency Escape:: What to do if Emacs stops responding. 160* Emergency Escape:: What to do if Emacs stops responding.
161* Long Lines:: Mitigating slowness due to extremely long lines.
162* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete. 161* DEL Does Not Delete:: What to do if @key{DEL} doesn't delete.
163@end menu 162@end menu
164 163
@@ -433,64 +432,6 @@ program.
433emergency escape---but there are cases where it won't work, when a 432emergency escape---but there are cases where it won't work, when a
434system call hangs or when Emacs is stuck in a tight loop in C code. 433system call hangs or when Emacs is stuck in a tight loop in C code.
435 434
436@node Long Lines
437@subsection Long Lines
438@cindex long lines
439
440 For a variety of reasons (some of which are fundamental to the Emacs
441redisplay code and the complex range of possibilities it handles;
442others of which are due to modes and features which do not scale well
443in unusual circumstances), Emacs can perform poorly when extremely
444long lines are present (where ``extremely long'' usually means at
445least many thousands of characters).
446
447@cindex @code{so-long} mode
448@findex global-so-long-mode
449@vindex so-long-action
450 A particular problem is that Emacs may ``hang'' for a long time at
451the point of visiting a file with extremely long lines. This can be
452mitigated by enabling the @file{so-long} library, which detects when a
453visited file contains abnormally long lines, and takes steps to
454disable features which are liable to cause slowness in that situation.
455To enable this library, type @kbd{M-x global-so-long-mode @key{RET}},
456or turn on the @code{global-so-long-mode} in your init file
457(@pxref{Init File}), or customize the @code{global-so-long-mode}
458option. You can tailor this mode's operation by customizing the
459variable @code{so-long-action}.
460
461 The @file{so-long} library can also significantly improve
462performance when moving and editing in a buffer with long lines.
463Performance is still likely to degrade as you get deeper into the long
464lines, but the improvements from using this library can nevertheless
465be substantial.
466
467@findex so-long-commentary
468 Use @kbd{M-x so-long-commentary} to view the documentation for this
469library and learn more about how to enable and configure it.
470
471@vindex max-redisplay-ticks
472 If even @code{so-long-mode} doesn't help making Emacs responsive
473enough, or if you'd rather not disable the display-related features
474that @code{so-long-mode} turns off, you can instead customize the
475variable @code{max-redisplay-ticks} to a non-zero value. Then Emacs
476will abort redisplay of a window and commands, like @kbd{C-n} and
477@kbd{M-v}, which use the display code to do their job, if processing a
478window needs more low-level display operations than the value of this
479variable. The display of the offending window will then remain
480outdated, and possibly incomplete, on the screen, but Emacs should
481otherwise be responsive, and you could then switch to another buffer,
482or kill the problematic buffer, or turn on @code{so-long-mode} or
483@code{so-long-minor-mode} in that buffer. When the display of a
484window is aborted due to this reason, the buffer shown in that window
485will not have any of its windows redisplayed until the buffer is
486modified or until you type @kbd{C-l} (@pxref{Recentering}) in one of
487that buffer's windows.
488
489 If you decide to customize this variable to a non-zero value, we
490recommend to use a value between 100,000 and 1,000,000, depending on
491your patience and the speed of your system. The default value is
492zero, which disables this feature.
493
494@node DEL Does Not Delete 435@node DEL Does Not Delete
495@subsection If @key{DEL} Fails to Delete 436@subsection If @key{DEL} Fails to Delete
496@cindex @key{DEL} vs @key{BACKSPACE} 437@cindex @key{DEL} vs @key{BACKSPACE}
diff --git a/etc/NEWS b/etc/NEWS
index 7a1b7a856af..223e6dd7616 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -325,7 +325,14 @@ startup. Previously, these functions ignored
325* Changes in Emacs 29.1 325* Changes in Emacs 29.1
326 326
327--- 327---
328** 'longlines-mode' is no longer obsolete. 328** Emacs is now capable of editing files with arbitarily long lines.
329The display of long lines has been optimized, and Emacs no longer
330chokes when a buffer on display contains long lines. If you still
331experience slowdowns while editing files with long lines, this is
332either due to font locking, which you can turn off with M-x
333font-lock-mode, or to the current major mode or one of the enabled
334minor modes, in which case you should open the the file with M-x
335find-file-literally instead of C-x C-f.
329 336
330+++ 337+++
331** New command to change the font size globally. 338** New command to change the font size globally.
@@ -347,10 +354,10 @@ Get the parent directory of a file.
347This variable is used by some operations (mostly syntax-propertization 354This variable is used by some operations (mostly syntax-propertization
348and font-locking) to treat lines longer than this variable as if they 355and font-locking) to treat lines longer than this variable as if they
349were made up of various smaller lines. This can help reduce the 356were made up of various smaller lines. This can help reduce the
350pathological slowdowns seen in buffers made of a single long line, but 357slowdowns seen in buffers made of a single long line, but can also
351can also cause misbehavior in the presence of such long lines (tho 358cause misbehavior in the presence of such long lines (tho most of that
352most of that misbehavior should usually be limited to mis-highlighting). 359misbehavior should usually be limited to mis-highlighting). You can
353You can recover the previous behavior with: 360recover the previous behavior with:
354 361
355 (setq syntax-wholeline-max most-positive-fixnum) 362 (setq syntax-wholeline-max most-positive-fixnum)
356 363
@@ -463,11 +470,6 @@ previous behavior). The default is nil, which inhibits recording of
463passwords. 470passwords.
464 471
465+++ 472+++
466** New user option 'longlines-breakpoint-chars'.
467This is a string containing chars that could be used as breakpoint in
468longlines mode.
469
470+++
471** New function 'command-query'. 473** New function 'command-query'.
472This function makes its argument command prompt the user for 474This function makes its argument command prompt the user for
473confirmation before executing. 475confirmation before executing.
diff --git a/lisp/longlines.el b/lisp/obsolete/longlines.el
index a6cf93a0394..d44a634e2e0 100644
--- a/lisp/longlines.el
+++ b/lisp/obsolete/longlines.el
@@ -6,6 +6,7 @@
6;; Alex Schroeder <alex@gnu.org> 6;; Alex Schroeder <alex@gnu.org>
7;; Chong Yidong <cyd@stupidchicken.com> 7;; Chong Yidong <cyd@stupidchicken.com>
8;; Maintainer: emacs-devel@gnu.org 8;; Maintainer: emacs-devel@gnu.org
9;; Obsolete-since: 24.4
9;; Keywords: convenience, wp 10;; Keywords: convenience, wp
10 11
11;; This file is part of GNU Emacs. 12;; This file is part of GNU Emacs.
diff --git a/src/composite.c b/src/composite.c
index 4d69702171f..d8998b5a1f3 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -1576,6 +1576,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
1576 Lisp_Object window; 1576 Lisp_Object window;
1577 struct window *w; 1577 struct window *w;
1578 bool need_adjustment = 0; 1578 bool need_adjustment = 0;
1579 ptrdiff_t narrowed_begv;
1579 1580
1580 window = Fget_buffer_window (Fcurrent_buffer (), Qnil); 1581 window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
1581 if (NILP (window)) 1582 if (NILP (window))
@@ -1586,6 +1587,11 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
1586 if (NILP (string)) 1587 if (NILP (string))
1587 { 1588 {
1588 head = backlim < 0 ? BEGV : backlim, tail = ZV, stop = GPT; 1589 head = backlim < 0 ? BEGV : backlim, tail = ZV, stop = GPT;
1590 /* In buffers with very long lines, this function becomes very
1591 slow. Pretend that the buffer is narrowed to make it fast. */
1592 narrowed_begv = get_narrowed_begv (w);
1593 if (pos > narrowed_begv)
1594 head = narrowed_begv;
1589 cur.pos_byte = CHAR_TO_BYTE (cur.pos); 1595 cur.pos_byte = CHAR_TO_BYTE (cur.pos);
1590 cur.p = BYTE_POS_ADDR (cur.pos_byte); 1596 cur.p = BYTE_POS_ADDR (cur.pos_byte);
1591 } 1597 }
diff --git a/src/dispextern.h b/src/dispextern.h
index ca7834dec55..2edf4b73f81 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2332,6 +2332,10 @@ struct it
2332 with which display_string was called. */ 2332 with which display_string was called. */
2333 ptrdiff_t end_charpos; 2333 ptrdiff_t end_charpos;
2334 2334
2335 /* Alternate begin position of the buffer, which is used to optimize
2336 display (see the WITH_NARROWED_BEGV macro below). */
2337 ptrdiff_t narrowed_begv;
2338
2335 /* C string to iterate over. Non-null means get characters from 2339 /* C string to iterate over. Non-null means get characters from
2336 this string, otherwise characters are read from current_buffer 2340 this string, otherwise characters are read from current_buffer
2337 or it->string. */ 2341 or it->string. */
@@ -2813,6 +2817,18 @@ struct it
2813 reset_box_start_end_flags ((IT)); \ 2817 reset_box_start_end_flags ((IT)); \
2814 } while (false) 2818 } while (false)
2815 2819
2820/* Execute STATEMENT with a temporarily narrowed buffer. */
2821
2822#define WITH_NARROWED_BEGV(STATEMENT) \
2823 do { \
2824 ptrdiff_t obegv = BEGV; \
2825 if (it->narrowed_begv) \
2826 SET_BUF_BEGV (current_buffer, it->narrowed_begv); \
2827 STATEMENT; \
2828 if (it->narrowed_begv) \
2829 SET_BUF_BEGV (current_buffer, obegv); \
2830 } while (0)
2831
2816/* Bit-flags indicating what operation move_it_to should perform. */ 2832/* Bit-flags indicating what operation move_it_to should perform. */
2817 2833
2818enum move_operation_enum 2834enum move_operation_enum
@@ -3396,6 +3412,7 @@ void mark_window_display_accurate (Lisp_Object, bool);
3396void redisplay_preserve_echo_area (int); 3412void redisplay_preserve_echo_area (int);
3397void init_iterator (struct it *, struct window *, ptrdiff_t, 3413void init_iterator (struct it *, struct window *, ptrdiff_t,
3398 ptrdiff_t, struct glyph_row *, enum face_id); 3414 ptrdiff_t, struct glyph_row *, enum face_id);
3415ptrdiff_t get_narrowed_begv (struct window *w);
3399void init_iterator_to_row_start (struct it *, struct window *, 3416void init_iterator_to_row_start (struct it *, struct window *,
3400 struct glyph_row *); 3417 struct glyph_row *);
3401void start_display (struct it *, struct window *, struct text_pos); 3418void start_display (struct it *, struct window *, struct text_pos);
diff --git a/src/window.c b/src/window.c
index af463b90ce6..61ca9feb64d 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1028,7 +1028,7 @@ window_body_unit_from_symbol (Lisp_Object unit)
1028/* Return the number of lines/pixels of W's body. Don't count any mode 1028/* Return the number of lines/pixels of W's body. Don't count any mode
1029 or header line or horizontal divider of W. Rounds down to nearest 1029 or header line or horizontal divider of W. Rounds down to nearest
1030 integer when not working pixelwise. */ 1030 integer when not working pixelwise. */
1031static int 1031int
1032window_body_height (struct window *w, enum window_body_unit pixelwise) 1032window_body_height (struct window *w, enum window_body_unit pixelwise)
1033{ 1033{
1034 int height = (w->pixel_height 1034 int height = (w->pixel_height
diff --git a/src/window.h b/src/window.h
index 298a80a5366..c63b1b24d4f 100644
--- a/src/window.h
+++ b/src/window.h
@@ -1193,6 +1193,7 @@ enum window_body_unit
1193 WINDOW_BODY_IN_REMAPPED_CHARS 1193 WINDOW_BODY_IN_REMAPPED_CHARS
1194 }; 1194 };
1195extern int window_body_width (struct window *w, enum window_body_unit); 1195extern int window_body_width (struct window *w, enum window_body_unit);
1196extern int window_body_height (struct window *w, enum window_body_unit);
1196enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS }; 1197enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS };
1197extern int window_scroll_margin (struct window *, enum margin_unit); 1198extern int window_scroll_margin (struct window *, enum margin_unit);
1198extern void temp_output_buffer_show (Lisp_Object); 1199extern void temp_output_buffer_show (Lisp_Object);
diff --git a/src/xdisp.c b/src/xdisp.c
index 4089525e10f..e130b23d9a1 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -3425,6 +3425,8 @@ init_iterator (struct it *it, struct window *w,
3425 } 3425 }
3426 } 3426 }
3427 3427
3428 it->narrowed_begv = get_narrowed_begv (w);
3429
3428 /* If a buffer position was specified, set the iterator there, 3430 /* If a buffer position was specified, set the iterator there,
3429 getting overlays and face properties from that position. */ 3431 getting overlays and face properties from that position. */
3430 if (charpos >= BUF_BEG (current_buffer)) 3432 if (charpos >= BUF_BEG (current_buffer))
@@ -3491,6 +3493,19 @@ init_iterator (struct it *it, struct window *w,
3491 CHECK_IT (it); 3493 CHECK_IT (it);
3492} 3494}
3493 3495
3496/* Compute a suitable value for BEGV that can be used temporarily, to
3497 optimize display, for the buffer in window W. */
3498
3499ptrdiff_t
3500get_narrowed_begv (struct window *w)
3501{
3502 int len, begv;
3503 len = (1 + ((window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS) *
3504 window_body_height (w, WINDOW_BODY_IN_CANONICAL_CHARS)) /
3505 10000)) * 10000;
3506 begv = max ((PT / len - 2) * len, BEGV);
3507 return begv == BEGV ? 0 : begv;
3508}
3494 3509
3495/* Initialize IT for the display of window W with window start POS. */ 3510/* Initialize IT for the display of window W with window start POS. */
3496 3511
@@ -6992,7 +7007,8 @@ back_to_previous_line_start (struct it *it)
6992 ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it); 7007 ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
6993 7008
6994 dec_both (&cp, &bp); 7009 dec_both (&cp, &bp);
6995 IT_CHARPOS (*it) = find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)); 7010 WITH_NARROWED_BEGV (IT_CHARPOS (*it) =
7011 find_newline_no_quit (cp, bp, -1, &IT_BYTEPOS (*it)));
6996} 7012}
6997 7013
6998 7014
@@ -8623,7 +8639,9 @@ get_visually_first_element (struct it *it)
8623{ 8639{
8624 bool string_p = STRINGP (it->string) || it->s; 8640 bool string_p = STRINGP (it->string) || it->s;
8625 ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV); 8641 ptrdiff_t eob = (string_p ? it->bidi_it.string.schars : ZV);
8626 ptrdiff_t bob = (string_p ? 0 : BEGV); 8642 ptrdiff_t bob;
8643
8644 WITH_NARROWED_BEGV (bob = (string_p ? 0 : BEGV));
8627 8645
8628 if (STRINGP (it->string)) 8646 if (STRINGP (it->string))
8629 { 8647 {
@@ -8663,9 +8681,10 @@ get_visually_first_element (struct it *it)
8663 if (string_p) 8681 if (string_p)
8664 it->bidi_it.charpos = it->bidi_it.bytepos = 0; 8682 it->bidi_it.charpos = it->bidi_it.bytepos = 0;
8665 else 8683 else
8666 it->bidi_it.charpos = find_newline_no_quit (IT_CHARPOS (*it), 8684 WITH_NARROWED_BEGV (it->bidi_it.charpos =
8667 IT_BYTEPOS (*it), -1, 8685 find_newline_no_quit (IT_CHARPOS (*it),
8668 &it->bidi_it.bytepos); 8686 IT_BYTEPOS (*it), -1,
8687 &it->bidi_it.bytepos));
8669 bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true); 8688 bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, true);
8670 do 8689 do
8671 { 8690 {
@@ -10583,7 +10602,7 @@ move_it_vertically_backward (struct it *it, int dy)
10583 ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it); 10602 ptrdiff_t cp = IT_CHARPOS (*it), bp = IT_BYTEPOS (*it);
10584 10603
10585 dec_both (&cp, &bp); 10604 dec_both (&cp, &bp);
10586 cp = find_newline_no_quit (cp, bp, -1, NULL); 10605 WITH_NARROWED_BEGV (cp = find_newline_no_quit (cp, bp, -1, NULL));
10587 move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS); 10606 move_it_to (it, cp, -1, -1, -1, MOVE_TO_POS);
10588 } 10607 }
10589 bidi_unshelve_cache (it3data, true); 10608 bidi_unshelve_cache (it3data, true);