emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/fix-the-long-lines-display-bug 1792cbaddc: Actually fix the long


From: Gregory Heytings
Subject: feature/fix-the-long-lines-display-bug 1792cbaddc: Actually fix the long lines display bug (bug#56393).
Date: Fri, 8 Jul 2022 17:37:20 -0400 (EDT)

branch: feature/fix-the-long-lines-display-bug
commit 1792cbaddc33772c344e45fb9478bee85fee66e7
Author: Gregory Heytings <gregory@heytings.org>
Commit: Gregory Heytings <gregory@heytings.org>

    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.
---
 doc/emacs/emacs.texi             |  1 -
 doc/emacs/trouble.texi           | 59 ----------------------------------------
 etc/NEWS                         | 22 ++++++++-------
 lisp/{ => obsolete}/longlines.el |  1 +
 src/composite.c                  |  6 ++++
 src/dispextern.h                 | 17 ++++++++++++
 src/window.c                     |  2 +-
 src/window.h                     |  1 +
 src/xdisp.c                      | 31 +++++++++++++++++----
 9 files changed, 63 insertions(+), 77 deletions(-)

diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 5e72699bbe..b43c966f87 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -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
diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi
index f06b93759d..887e5c6170 100644
--- a/doc/emacs/trouble.texi
+++ b/doc/emacs/trouble.texi
@@ -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}
diff --git a/etc/NEWS b/etc/NEWS
index 7a1b7a856a..223e6dd761 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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
diff --git a/lisp/longlines.el b/lisp/obsolete/longlines.el
similarity index 99%
rename from lisp/longlines.el
rename to lisp/obsolete/longlines.el
index a6cf93a039..d44a634e2e 100644
--- a/lisp/longlines.el
+++ b/lisp/obsolete/longlines.el
@@ -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.
diff --git a/src/composite.c b/src/composite.c
index 4d69702171..d8998b5a1f 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,
   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);
     }
diff --git a/src/dispextern.h b/src/dispextern.h
index ca7834dec5..2edf4b73f8 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -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);
diff --git a/src/window.c b/src/window.c
index af463b90ce..61ca9feb64 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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
diff --git a/src/window.h b/src/window.h
index 298a80a536..c63b1b24d4 100644
--- a/src/window.h
+++ b/src/window.h
@@ -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);
diff --git a/src/xdisp.c b/src/xdisp.c
index 4089525e10..e130b23d9a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]