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

From: Dmitry Gutov <[email-masked]>
Date: Mon, 7 Dec 2020 04:41:09 +0200

On 06.12.2020 23:54, Juri Linkov wrote:
>>> OTOH, ripgrep has the suitable options:
>>>     -M, --max-columns NUM
>>>         Don’t print lines longer than this limit in bytes. Longer lines are omitted,
>>>         and only the number of matches in that line is printed.
>>>     --max-columns-preview
>>>         When the --max-columns flag is used, ripgrep will by default completely
>>>         replace any line that is too long with a message indicating that a matching
>>>         line was removed.  When this flag is combined with --max-columns, a preview
>>>         of the line (corresponding to the limit size) is shown instead, where the
>>>         part of the line exceeding the limit is not shown.
>>
>> You can experiment with these Right Now(tm) by customizing
>> xref-search-program-alist (as well as xref-search-program). They'll only
>> affect commands that use xref-matches-in-files, though.
> 
> You mean adding "-M 200 --max-columns-preview" to xref-search-program-alist?

Yup.

> It works nice, thanks.  Should this be added by default?

Maybe someday?

Currently, it has a certain side-effect: whenever there are matches that 
don't fit the specified width, they will be omitted from the resulting 
xref buffer. Depending on the user's intent, it can be a problem.

Perhaps they did, after all, intend to search that minified JS file as well?

This should be fixable (in xref--collect-matches-1, probably), but we'd 
have to consider carefully on what to do in situations like that. E.g., 
if we put some placeholder there, that would mean that "search and 
replace" won't work.

Alternatively, xref--collect-matches-1 could apply the limit itself, no 
matter whether grep or rg is used. And it could make sure to only do 
that after the last match. This might be the slower option, but hard to 
say in advance, some comparison benchmark could help here.

>>> Wouldn't it be unthinkable to add support of ripgrep to grep.el?
>>> This will allow switching to ripgrep when there is a need to
>>> search in files with long lines.
>>
>> I'm fairly sure nothing in terms of politics is stopping us here, but if we
>> wanted to update grep.el's abstractions to use different search programs,
>> it looks like a bigger job to me.
>>
>> Though maybe you can get away with customizing a select number of
>> variables? Like grep-template, grep-find-template, etc.
> 
> I customized grep-find-template to "find <D> <X> -type f <F> -print0 | sort -z |
>   xargs -0 -e rg -inH --color always --no-heading -M 200 --max-columns-preview -e <R>"
> 
> But this also requires customizing grep-match-regexp to the value
> "\033\\[[0-9]*m\033\\[[0-9]*1m\033\\[[0-9]*1m\\(.*?\\)\033\\[[0-9]*0m"
> provided by Simon in bug#41766.

It's odd your last suggestion in that bug was not applied (adding :type 
'(choice) to grep-match-regexp). Perhaps do that now?

Although, personally, I've found a symbolic value to work better for a 
var like that (example: xref-search-program). This way we can ultimately 
consolidate info about a particular program in one place (some alist).

That aside, could you explain the difference between the regexps? Do 
grep and rg use different colors or something like that? Ideally, of 
course, that would be just 1 regexp (if that's possible without loss in 
performance, or significant loss in clarify).

> And also required a small fix in grep.el:
> 
> diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
> index dafba22f77..0a5fd6bf5d 100644
> --- a/lisp/progmodes/grep.el
> +++ b/lisp/progmodes/grep.el
> @@ -412,7 +412,7 @@ grep-regexp-alist
>                  (- mend beg))))))
>        nil nil
>        (3 '(face nil display ":")))
> -    ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
> +    ("^Binary file \\(.+\\) matches" 1 nil nil 0 1))
>     "Regexp used to match grep hits.
>   See `compilation-error-regexp-alist' for format details.")

Nice.