Subject: bug#44983: Truncate long lines of grep output

From: Juri Linkov <[email-masked]>
Date: Thu, 03 Dec 2020 23:17:08 +0200

> And when you say "slow" do you mean slow in receiving Grep output,
> slow in displaying the received output, or slow in moving though the
> *grep* buffer after everything was displayed?

Slow in receiving, slow in displaying, or but not slow in moving
though the hidden parts of long lines.

>> Then instead of hiding long lines using font-lock,
>> I tried to do the same using the process filter:
>> 
>> (defun grep-filter ()
>>   (save-excursion
>>     (let ((end (point-marker)))
>>       (goto-char compilation-filter-start)
>>       (forward-line 0)
>>       (while (< (point) end)
>>         (let ((eol (line-end-position)))
>>           (when (> (- eol (point)) 64)
>>             (put-text-property (+ 64 (point)) (line-end-position)
>>                                'display "[…]"))
>>           (forward-line 1))))))
>> 
>> Still very slow.
>
> Same question as above.

Slow in receiving and slow in displaying.

>> Then tried to delete the excessive parts of long lines:
>> 
>> (defun grep-filter-try ()
>>   (save-excursion
>>     (let ((end (point-marker)))
>>       (goto-char compilation-filter-start)
>>       (forward-line 0)
>>       (while (< (point) end)
>>         (let ((eol (line-end-position)))
>>           (when (> (- eol (point)) 64)
>>             (delete-region (min (+ 64 (point)) (point-max)) (line-end-position)))
>>           (forward-line 1))))))
>> 
>> Now Emacs becomes more responsive.  But still output processing
>> takes too much time.
>
> What is "output processing", and how did you measure the time it
> takes?

Measuring visually, it takes too much time to output the long lines.

>> Finally, the last thing to try was the same solution that Richard
>> showed in bug#44941:
>> 
>>   grep -a "$@" | cut -c -200
>> 
>> that gives the best possible result.
>> 
>> I doubt that it would be possible to invent something better.
>> 
>> So the question is should this be customizable for adding
>> `cut -c` automatically to the end of the grep command line,
>> possibly with `stdbuf -oL` suggested by Andreas.
>
> I suggested to request the equivalent of "cut -c" to be a feature
> added to Grep.
>
> Failing that, I don't think Emacs should do something like that,
> especially since 'cut' is not guaranteed to be available.  Users who
> have such problems can, of course, modify the Grep command to do that.

Finally I solved the long-standing problem by customizing
grep-find-template to

  "find <D> <X> -type f <F> -print0 | sort -z | xargs -0 -e grep <C> --color=always -inH -e <R> | cut -c -200"

I'm not sure if something like this could be added to grep, but
here is an example how such a new option could look:

diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index dafba22f77..a5a2142a9e 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -534,6 +534,7 @@ grep-find-use-xargs
                  (const :tag "find -exec {} +" exec-plus)
                  (const :tag "find -print0 | xargs -0" gnu)
                  (const :tag "find -print0 | sort -z | xargs -0'" gnu-sort)
+                 (const :tag "find -print0 | sort -z | xargs -0' ... | cut -c -200" gnu-sort-cut)
                  string
 		 (const :tag "Not Set" nil))
   :set #'grep-apply-setting
@@ -722,7 +723,8 @@ grep-compute-defaults
 		     (goto-char (point-min))
 		     (search-forward "--color" nil t))
 		   ;; Windows and DOS pipes fail `isatty' detection in Grep.
-		   (if (memq system-type '(windows-nt ms-dos))
+		   (if (or (eq grep-find-use-xargs 'gnu-sort-cut)
+                           (memq system-type '(windows-nt ms-dos)))
 		       'always 'auto)))))
 
     (unless (and grep-command grep-find-command
@@ -775,6 +777,9 @@ grep-compute-defaults
 		      ((eq grep-find-use-xargs 'gnu-sort)
 		       (format "%s . -type f -print0 | sort -z | \"%s\" -0 %s"
 			       find-program xargs-program grep-command))
+		      ((eq grep-find-use-xargs 'gnu-sort-cut)
+		       (format "%s . -type f -print0 | sort -z | \"%s\" -0 %s | cut -c -200"
+			       find-program xargs-program grep-command))
 		      ((memq grep-find-use-xargs '(exec exec-plus))
 		       (let ((cmd0 (format "%s . -type f -exec %s"
 					   find-program grep-command))
@@ -803,6 +808,9 @@ grep-compute-defaults
 			((eq grep-find-use-xargs 'gnu-sort)
 			 (format "%s <D> <X> -type f <F> -print0 | sort -z | \"%s\" -0 %s"
 				 find-program xargs-program gcmd))
+			((eq grep-find-use-xargs 'gnu-sort-cut)
+			 (format "%s <D> <X> -type f <F> -print0 | sort -z | \"%s\" -0 %s | cut -c -200"
+				 find-program xargs-program gcmd))
 			((eq grep-find-use-xargs 'exec)
 			 (format "%s <D> <X> -type f <F> -exec %s %s %s%s"
 				 find-program gcmd quot-braces null quot-scolon))