Subject: bug#46859: 28.0.50; [PATCH]: Add option to truncate long lines in xref.el

From: Theodor Thornhill <[email-masked]>
Date: Mon, 01 Mar 2021 21:40:50 +0100

Hi!

When using the xref buffer, especially in combination with
'project-find-regexp', sometimes my projects has huge one-line
files. The simplest example of these kind of files are the minified
".js" files that are compiled. Right now I have one at 500 000 columns,
which admittedly is a lot. However, when 'project-find-regexp' searches
these files and finds a hit in one of them, the search takes a long
time. In addition, navigating the xref buffer when the results show up
also takes a long time, because of the troubles emacs has with long
lines.

Before the supplied patch, one search with 'project-find-regexp' with
ripgrep enabled takes around 3-4 seconds. With the supplied patch, the
search is almost instantaneous.

The added functionality is created to not kick in before a certain
threshold, where 500 columns seems reasonably long. Anything above that
will be truncated, but xref will still show that there was a hit.

I'm sure the patch can be improved, so please, don't hesitate to tell
me.

I consider this a great improvement, and I hope you will to§

Have a nice day,

--
Theodor Thornhill

>From dcc2078c20d8edd32407498c16d65ea46d44a3a0 Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <[email-masked]>
Date: Mon, 1 Mar 2021 21:26:44 +0100
Subject: [PATCH] Add option to truncate long lines

* (xref-truncate-line-to): New option.  Set cut-off point for long
lines in xref buffer

* (xref--truncate-long-lines-p): Helper function for xref--insert-xrefs.

* (xref--insert-xrefs): By truncating long lines we get a huge speedup
both when invoking xref, and while navigating the xref buffer.
---
 lisp/progmodes/xref.el | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 18fdd963fb..98dacef94f 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -872,6 +872,19 @@ beginning of the line."
       (xref--search-property 'xref-item))
   (xref-show-location-at-point))
 
+(defcustom xref-truncate-line-to 500
+  "Max number of columns to display in xref buffer."
+  :type '(choice
+          (fixnum :tag "Number of lines")
+          (null :tag "Don't truncate"))
+  :version "28.1"
+  :package-version '(xref . "1.0.5"))
+
+(defun xref--truncate-long-lines-p (summary)
+  (cl-check-type summary xref-item)
+  (and (numberp xref-truncate-line-to)
+       (> (length summary) xref-truncate-line-to)))
+
 (defun xref--insert-xrefs (xref-alist)
   "Insert XREF-ALIST in the current-buffer.
 XREF-ALIST is of the form ((GROUP . (XREF ...)) ...), where
@@ -902,14 +915,24 @@ GROUP is a string for decoration purposes and XREF is an
                                 "  ")))
                         ;; Render multiple matches on the same line, together.
                         (when (and line (equal prev-line-key line-key))
-                          (when-let ((column (xref-location-column location)))
-                            (delete-region
-                             (save-excursion
-                               (forward-line -1)
-                               (move-to-column (+ (length prefix) column))
+                          ;; Overwrite if we want to truncate long lines.
+                          (if (xref-truncate-long-lines-p new-summary)
+                              (delete-region
+                               (save-excursion (forward-line -1) (point))
+                               (point))
+                            (when-let ((column (xref-location-column location)))
+                              (delete-region
+                               (save-excursion
+                                 (forward-line -1)
+                                 (move-to-column (+ (length prefix) column))
+                                 (point))
                                (point))
-                             (point))
-                            (setq new-summary (substring summary column) prefix "")))
+                              (setq new-summary (substring summary column) prefix ""))))
+                        ;; Truncate
+                        (when (xref-truncate-long-lines-p new-summary)
+                          (setq new-summary
+                                (concat (substring new-summary 0 xref-truncate-line-to)
+                                        " (...truncated)")))
                         (xref--insert-propertized
                          (list 'xref-item xref
                                'mouse-face 'highlight
-- 
2.24.3 (Apple Git-128)