all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#59888: [PATCH] Add 'grep-heading-mode'
@ 2022-12-07 17:57 Augusto Stoffel
  2022-12-07 18:14 ` Eli Zaretskii
                   ` (3 more replies)
  0 siblings, 4 replies; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-07 17:57 UTC (permalink / raw)
  To: 59888

[-- Attachment #1: Type: text/plain, Size: 763 bytes --]

Tags: patch

This simulates the --heading option of certain grep-like tools.  The
output is like this:

--8<---------------cut here---------------start------------->8---
-*- mode: grep; default-directory: "~/Projects/emacs/" -*-
Grep started at Wed Dec  7 18:43:40

find [...] -exec grep --color=auto -i -nH --null -e test \{\} +

./nextstep/Makefile.in
104:	find ${ns_appdir} -exec test \! -e {} \; -ls

./nextstep/INSTALL
12:Tested on GNU/Linux, may work on other systems.

./nextstep/Makefile
104:	find ${ns_appdir} -exec test \! -e {} \; -ls

./nextstep/README
62:  10.6.8 (Snow Leopard) to the latest official release.
86:* This allows other Emacs developers to test their changes on the NS
--8<---------------cut here---------------end--------------->8---


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-grep-heading-mode.patch --]
[-- Type: text/patch, Size: 4316 bytes --]

From 2247f006845000032fedc3dda9a073b14043a270 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Wed, 7 Dec 2022 18:44:07 +0100
Subject: [PATCH] Add 'grep-heading-mode'

New minor mode to subdivide grep output into sections, as in the
'--heading' option of certain grep-like programs.

* lisp/progmodes/grep.el (grep-heading-regexp): New user option.
(grep-heading): New face.
(grep--heading-format, grep--current-heading, grep--heading-filter):
Filter function for grep processes and supporting variables.
(grep-heading-mode): New minor mode.
---
 etc/NEWS               |  8 +++++
 lisp/progmodes/grep.el | 71 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 3eeef0ab4c..54c3b2447a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -41,6 +41,14 @@ connection.
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
+** Compile
+
+*** New minor mode 'grep-heading-mode'.
+In this mode, the grep output is split into sections, one for each
+file, instead of having file names prefixed to each line.  It is
+equivalent to the --heading option of some tools such as 'git grep'
+and 'rg.
+
 ** VC
 
 ---
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 2446e86abb..132f905734 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -30,6 +30,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'rx))
 (require 'compile)
 
 (defgroup grep nil
@@ -1407,6 +1408,76 @@ grep-file-at-point
 ;;;###autoload
 (defalias 'rzgrep #'zrgrep)
 
+;;; Headings mode
+(defcustom grep-heading-regexp
+  (rx bol
+      (or
+       (seq "Grep" (* (any "/a-zA-Z")) " "
+            (or "started" "finished" "exited" "interrupt" "killed" "terminated")
+            (* (not (any "\0\n"))))
+       (seq
+        (group-n 2
+          (group-n 1 (+? any))
+          (any "\0-:="))
+        (+ digit)
+        (any "-:="))))
+  "Regexp used to create headings from grep output lines.
+It should be anchored at beginning of line.  The first capture
+group, if present, should match the heading associated to the
+line.  The buffer range of the second capture, if present, is
+made invisible (presumably because displaying it would be
+redundant)."
+  :type 'regexp
+  :version "30.1")
+
+(defface grep-heading '((t :inherit font-lock-function-name-face))
+  "Face of headings when using `grep-heading-mode'.")
+
+(defvar grep--heading-format
+  #("\n%s\n" 1 3 (font-lock-face grep-heading outline-level 1))
+  "Format string of grep headings.
+This is passed to `format' with one argument, the text of the
+first capture group of `grep-heading-regexp'.")
+
+(defvar-local grep--current-heading nil
+  "Used by `grep--heading-filter' to keep track of the current heading.")
+
+(defun grep--heading-filter ()
+  "Filter function to add headings to output of a grep process."
+  (save-excursion
+    (let ((bound (copy-marker (pos-bol))))
+      (goto-char compilation-filter-start)
+      (forward-line 0)
+      (while (re-search-forward grep-heading-regexp bound t)
+        (let ((heading (match-string-no-properties 1))
+              (start (match-beginning 2))
+              (end (match-end 2)))
+          (when start
+            (put-text-property start end 'invisible t))
+          (when (and heading (not (equal heading grep--current-heading)))
+            (save-excursion
+              (forward-line 0)
+              (insert-before-markers (format grep--heading-format heading)))
+            (setq grep--current-heading heading)))))))
+
+;;;###autoload
+(define-minor-mode grep-heading-mode
+  "Subdivide grep output into sections, one per file."
+  :interactive 'grep-mode
+  (if (not grep-heading-mode)
+      (recompile)
+    (save-excursion
+      (save-restriction
+        (widen)
+        (let ((inhibit-read-only t)
+              (compilation-filter-start (point-min)))
+          (goto-char (point-max))
+          (grep--heading-filter))))
+    (add-hook 'compilation-filter-hook #'grep--heading-filter 80 t)
+    (setq-local outline-search-function #'outline-search-level
+                outline-level (lambda () (get-text-property
+                                          (point) 'outline-level)))))
+
 (provide 'grep)
 
 ;;; grep.el ends here
-- 
2.38.1


[-- Attachment #3: Type: text/plain, Size: 539 bytes --]


Some comments:

1. It's necessary to insert text into the grep buffer, which is a bit
   concerning because 'compilation-filter-start' is not a marker, just a
   number.  This could cause other filter functions to get confused.
   This is why I'm adding to 'compilation-filter-hook at a higher depth.
   Perhaps there are better approaches here.

2. One could get rid of the awkward first alternative of
   `grep-heading-regexp' if there was a way to distringuish the grep
   process output from the header and footer added by grep-mode.

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-07 17:57 bug#59888: [PATCH] Add 'grep-heading-mode' Augusto Stoffel
@ 2022-12-07 18:14 ` Eli Zaretskii
  2022-12-08  8:59   ` Augusto Stoffel
  2022-12-08  0:19 ` Stefan Kangas
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2022-12-07 18:14 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

> From: Augusto Stoffel <arstoffel@gmail.com>
> Date: Wed, 07 Dec 2022 18:57:37 +0100
> 
> +(defcustom grep-heading-regexp
> +  (rx bol
> +      (or
> +       (seq "Grep" (* (any "/a-zA-Z")) " "
> +            (or "started" "finished" "exited" "interrupt" "killed" "terminated")

Cannot these be translated to languages other than English in
localized versions of Grep?

> 2. One could get rid of the awkward first alternative of
>    `grep-heading-regexp' if there was a way to distringuish the grep
>    process output from the header and footer added by grep-mode.

You could put a special text property on the latter, no?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-07 17:57 bug#59888: [PATCH] Add 'grep-heading-mode' Augusto Stoffel
  2022-12-07 18:14 ` Eli Zaretskii
@ 2022-12-08  0:19 ` Stefan Kangas
  2022-12-08  9:06   ` Augusto Stoffel
  2022-12-08  9:57 ` bug#59888: [PATCH] Add 'grep-heading-mode' Mattias Engdegård
  2022-12-09  7:28 ` Juri Linkov
  3 siblings, 1 reply; 37+ messages in thread
From: Stefan Kangas @ 2022-12-08  0:19 UTC (permalink / raw)
  To: Augusto Stoffel, 59888

Augusto Stoffel <arstoffel@gmail.com> writes:

> From 2247f006845000032fedc3dda9a073b14043a270 Mon Sep 17 00:00:00 2001
> From: Augusto Stoffel <arstoffel@gmail.com>
> Date: Wed, 7 Dec 2022 18:44:07 +0100
> Subject: [PATCH] Add 'grep-heading-mode'
>
> New minor mode to subdivide grep output into sections, as in the
> '--heading' option of certain grep-like programs.
>
> * lisp/progmodes/grep.el (grep-heading-regexp): New user option.
> (grep-heading): New face.
> (grep--heading-format, grep--current-heading, grep--heading-filter):
> Filter function for grep processes and supporting variables.
> (grep-heading-mode): New minor mode.

How about making this into a defcustom instead of a minor mode?

I'm thinking that something like

    (setopt grep-use-headings t)

is a slightly simpler interface to use than

    (add-hook 'grep-mode-hook 'grep-heading-mode)

I also think the former plays a bit better with customize.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-07 18:14 ` Eli Zaretskii
@ 2022-12-08  8:59   ` Augusto Stoffel
  2022-12-08 10:57     ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-08  8:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 59888

On Wed,  7 Dec 2022 at 20:14, Eli Zaretskii wrote:

>> From: Augusto Stoffel <arstoffel@gmail.com>
>> Date: Wed, 07 Dec 2022 18:57:37 +0100
>> 
>> +(defcustom grep-heading-regexp
>> +  (rx bol
>> +      (or
>> +       (seq "Grep" (* (any "/a-zA-Z")) " "
>> +            (or "started" "finished" "exited" "interrupt" "killed" "terminated")
>
> Cannot these be translated to languages other than English in
> localized versions of Grep?

AFAICT these messages are generated by Emacs itself.

We could also use "^Grep[/a-zA-Z]* [^\0t\]*$" here, which has a slightly
higher change of being confused with actual grep output, but only when
not using grep --null.

>> 2. One could get rid of the awkward first alternative of
>>    `grep-heading-regexp' if there was a way to distringuish the grep
>>    process output from the header and footer added by grep-mode.
>
> You could put a special text property on the latter, no?

That's an option and it would be useful for other extensions as well.
So we would define something like

--8<---------------cut here---------------start------------->8---
(defun compilation-insert-note (&rest args)
  (let ((start (point)))
    (apply #'insert args)
    (put-text-property start (point) 'compilation-note t)))
--8<---------------cut here---------------end--------------->8---

and use throughout compile.el, right?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-08  0:19 ` Stefan Kangas
@ 2022-12-08  9:06   ` Augusto Stoffel
  2022-12-09  7:23     ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-08  9:06 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: 59888

On Wed,  7 Dec 2022 at 16:19, Stefan Kangas wrote:

> Augusto Stoffel <arstoffel@gmail.com> writes:
>
>> From 2247f006845000032fedc3dda9a073b14043a270 Mon Sep 17 00:00:00 2001
>> From: Augusto Stoffel <arstoffel@gmail.com>
>> Date: Wed, 7 Dec 2022 18:44:07 +0100
>> Subject: [PATCH] Add 'grep-heading-mode'
>>
>> New minor mode to subdivide grep output into sections, as in the
>> '--heading' option of certain grep-like programs.
>>
>> * lisp/progmodes/grep.el (grep-heading-regexp): New user option.
>> (grep-heading): New face.
>> (grep--heading-format, grep--current-heading, grep--heading-filter):
>> Filter function for grep processes and supporting variables.
>> (grep-heading-mode): New minor mode.
>
> How about making this into a defcustom instead of a minor mode?
>
> I'm thinking that something like
>
>     (setopt grep-use-headings t)
>
> is a slightly simpler interface to use than
>
>     (add-hook 'grep-mode-hook 'grep-heading-mode)
>
> I also think the former plays a bit better with customize.

This is at the same time less customizable in the sense that something
like

  (add-hook 'grep-mode-hook
    (lambda () (when condition) (setq grep-use-headings t)))

will not work (I think), while conditionally activating a minor mode
certainly works.  But I'm open to both approaches.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-07 17:57 bug#59888: [PATCH] Add 'grep-heading-mode' Augusto Stoffel
  2022-12-07 18:14 ` Eli Zaretskii
  2022-12-08  0:19 ` Stefan Kangas
@ 2022-12-08  9:57 ` Mattias Engdegård
  2022-12-08 10:28   ` Augusto Stoffel
  2022-12-09  7:28 ` Juri Linkov
  3 siblings, 1 reply; 37+ messages in thread
From: Mattias Engdegård @ 2022-12-08  9:57 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

No argument about the idea (good to me) or implementation but minor points regarding the regexp:

> +          (group-n 1 (+? any))

Very much prefer `nonl` or `not-newline` to `any`, which is only there for compatibility (shouldn't have been included in the first place).

> +          (any "\0-:="))

Is the range (ASCII 00..1A) intended here, or should that be a literal hyphen?
If the former, it should probably be made more explicit since that range includes all sorts of numbers, symbols and control chars and it kind of looks like it may be a mistake.






^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-08  9:57 ` bug#59888: [PATCH] Add 'grep-heading-mode' Mattias Engdegård
@ 2022-12-08 10:28   ` Augusto Stoffel
  2022-12-08 10:48     ` Mattias Engdegård
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-08 10:28 UTC (permalink / raw)
  To: Mattias Engdegård; +Cc: 59888

On Thu,  8 Dec 2022 at 10:57, Mattias Engdegård wrote:

> No argument about the idea (good to me) or implementation but minor points regarding the regexp:
>
>> +          (group-n 1 (+? any))
>
> Very much prefer `nonl` or `not-newline` to `any`, which is only there for compatibility (shouldn't have been included in the first place).

Hum, not-newline is too long, so this leaves an option between the
slightly deceiving and the quite obscure.

Okay, now I see `any' is not even documented.

>> +          (any "\0-:="))
>
> Is the range (ASCII 00..1A) intended here, or should that be a literal hyphen?
> If the former, it should probably be made more explicit since that
> range includes all sorts of numbers, symbols and control chars and it
> kind of looks like it may be a mistake.

The literal hyphen, which prefixes context lines in `grep -C <n>'.
Thanks for the heads up.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-08 10:28   ` Augusto Stoffel
@ 2022-12-08 10:48     ` Mattias Engdegård
  2023-02-27 14:18       ` Mattias Engdegård
  0 siblings, 1 reply; 37+ messages in thread
From: Mattias Engdegård @ 2022-12-08 10:48 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

8 dec. 2022 kl. 11.28 skrev Augusto Stoffel <arstoffel@gmail.com>:

>> Very much prefer `nonl` or `not-newline` to `any`, which is only there for compatibility (shouldn't have been included in the first place).
> 
> Hum, not-newline is too long, so this leaves an option between the
> slightly deceiving and the quite obscure.

Actually `nonl` isn't too bad once you get used to it. Pronounce it 'nonnel', stress on the first syllable.

> Okay, now I see `any' is not even documented.

Yes, it was inherited from the defunct `sregex` package, in hindsight a clear mistake.






^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-08  8:59   ` Augusto Stoffel
@ 2022-12-08 10:57     ` Eli Zaretskii
  0 siblings, 0 replies; 37+ messages in thread
From: Eli Zaretskii @ 2022-12-08 10:57 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

> From: Augusto Stoffel <arstoffel@gmail.com>
> Cc: 59888@debbugs.gnu.org
> Date: Thu, 08 Dec 2022 09:59:46 +0100
> 
> On Wed,  7 Dec 2022 at 20:14, Eli Zaretskii wrote:
> 
> >> From: Augusto Stoffel <arstoffel@gmail.com>
> >> Date: Wed, 07 Dec 2022 18:57:37 +0100
> >> 
> >> +(defcustom grep-heading-regexp
> >> +  (rx bol
> >> +      (or
> >> +       (seq "Grep" (* (any "/a-zA-Z")) " "
> >> +            (or "started" "finished" "exited" "interrupt" "killed" "terminated")
> >
> > Cannot these be translated to languages other than English in
> > localized versions of Grep?
> 
> AFAICT these messages are generated by Emacs itself.

All of them?

> We could also use "^Grep[/a-zA-Z]* [^\0t\]*$" here

The [/a-zA-Z] part is still ASCII-only, and I believe the "/" part
means you want to support file names? then for Windows we also need
the colon ':'.

> >> 2. One could get rid of the awkward first alternative of
> >>    `grep-heading-regexp' if there was a way to distringuish the grep
> >>    process output from the header and footer added by grep-mode.
> >
> > You could put a special text property on the latter, no?
> 
> That's an option and it would be useful for other extensions as well.
> So we would define something like
> 
> --8<---------------cut here---------------start------------->8---
> (defun compilation-insert-note (&rest args)
>   (let ((start (point)))
>     (apply #'insert args)
>     (put-text-property start (point) 'compilation-note t)))
> --8<---------------cut here---------------end--------------->8---
> 
> and use throughout compile.el, right?

Yes, something like this.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-08  9:06   ` Augusto Stoffel
@ 2022-12-09  7:23     ` Juri Linkov
  2022-12-09 11:58       ` Augusto Stoffel
  2022-12-09 12:18       ` bug#59888: [PATCH] Add 'grep-use-headings' Augusto Stoffel
  0 siblings, 2 replies; 37+ messages in thread
From: Juri Linkov @ 2022-12-09  7:23 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Stefan Kangas, 59888

>> How about making this into a defcustom instead of a minor mode?
>>
>> I'm thinking that something like
>>
>>     (setopt grep-use-headings t)
>>
>> is a slightly simpler interface to use than
>>
>>     (add-hook 'grep-mode-hook 'grep-heading-mode)
>>
>> I also think the former plays a bit better with customize.
>
> This is at the same time less customizable in the sense that something
> like
>
>   (add-hook 'grep-mode-hook
>     (lambda () (when condition) (setq grep-use-headings t)))
>
> will not work (I think), while conditionally activating a minor mode
> certainly works.  But I'm open to both approaches.

Why not?  (setq-local grep-use-headings t) definitely should do
the right thing.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-07 17:57 bug#59888: [PATCH] Add 'grep-heading-mode' Augusto Stoffel
                   ` (2 preceding siblings ...)
  2022-12-08  9:57 ` bug#59888: [PATCH] Add 'grep-heading-mode' Mattias Engdegård
@ 2022-12-09  7:28 ` Juri Linkov
  2022-12-09 11:58   ` Augusto Stoffel
  3 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2022-12-09  7:28 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

> Subject: [PATCH] Add 'grep-heading-mode'
>
> New minor mode to subdivide grep output into sections, as in the
> '--heading' option of certain grep-like programs.
>
> * lisp/progmodes/grep.el (grep-heading-regexp): New user option.
> (grep-heading): New face.
> (grep--heading-format, grep--current-heading, grep--heading-filter):
> Filter function for grep processes and supporting variables.
> (grep-heading-mode): New minor mode.

Thanks, this would be a great addition.

> +(defface grep-heading '((t :inherit font-lock-function-name-face))
> +  "Face of headings when using `grep-heading-mode'.")

I suggest to keep the existing color scheme, thus inheriting from
compilation-info.  This is the same color used by both grep.el and
xref.el by default.

> +(defvar grep--heading-format
> +  #("\n%s\n" 1 3 (font-lock-face grep-heading outline-level 1))

xref.el doesn't insert extra newlines between file sections.
It would be nice to keep the output closer to the existing
output in xref buffers.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-09  7:23     ` Juri Linkov
@ 2022-12-09 11:58       ` Augusto Stoffel
  2022-12-09 12:18       ` bug#59888: [PATCH] Add 'grep-use-headings' Augusto Stoffel
  1 sibling, 0 replies; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-09 11:58 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Stefan Kangas, 59888

On Fri,  9 Dec 2022 at 09:23, Juri Linkov wrote:

>>> How about making this into a defcustom instead of a minor mode?
>>>
>>> I'm thinking that something like
>>>
>>>     (setopt grep-use-headings t)
>>>
>>> is a slightly simpler interface to use than
>>>
>>>     (add-hook 'grep-mode-hook 'grep-heading-mode)
>>>
>>> I also think the former plays a bit better with customize.
>>
>> This is at the same time less customizable in the sense that something
>> like
>>
>>   (add-hook 'grep-mode-hook
>>     (lambda () (when condition) (setq grep-use-headings t)))
>>
>> will not work (I think), while conditionally activating a minor mode
>> certainly works.  But I'm open to both approaches.
>
> Why not?  (setq-local grep-use-headings t) definitely should do
> the right thing.

The variable has to be set at the moment `grep-mode' runs, while a minor
mode could be set at a later point.  But I agree a variable is
sufficient here, so I will make this change.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-09  7:28 ` Juri Linkov
@ 2022-12-09 11:58   ` Augusto Stoffel
  0 siblings, 0 replies; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-09 11:58 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 59888

On Fri,  9 Dec 2022 at 09:28, Juri Linkov wrote:

>> +(defface grep-heading '((t :inherit font-lock-function-name-face))
>> +  "Face of headings when using `grep-heading-mode'.")
>
> I suggest to keep the existing color scheme, thus inheriting from
> compilation-info.  This is the same color used by both grep.el and
> xref.el by default.

Yes, I came to the same conclusion in the meanwhile.

>> +(defvar grep--heading-format
>> +  #("\n%s\n" 1 3 (font-lock-face grep-heading outline-level 1))
>
> xref.el doesn't insert extra newlines between file sections.
> It would be nice to keep the output closer to the existing
> output in xref buffers.

Okay, I agree with your reasoning and will make the change.  However, I
must say find the result less appealing.  Note that, because of the lack
of newlines, xref-file-header was naturally chosen as a heavier face.

But it's all customizable anyway.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09  7:23     ` Juri Linkov
  2022-12-09 11:58       ` Augusto Stoffel
@ 2022-12-09 12:18       ` Augusto Stoffel
  2022-12-09 19:36         ` Eli Zaretskii
  1 sibling, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-09 12:18 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Lars Ingebrigtsen, Eli Zaretskii, Stefan Kangas, 59888

[-- Attachment #1: Type: text/plain, Size: 659 bytes --]

Here is an updated patch for the “grep headings” feature.

As discussed before, I introduced a text property so that one can tell
without guessing which parts of the compilation buffer are not coming
from the external process.  This seems to supersede the
'compilation-header-end' property introduced by Lars in commit
07f748da43, so I replaced its uses by the new 'compilation-aside'
property.  I could easily revert that, but it seemed reasonable to
uniformize things in this case.

I've also incorporated all other suggestions from other messages.  (And
Juri, nevermind what I said about some faces, it only applies to the
Modus theme.)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Introduce-compilation-aside-text-property.patch --]
[-- Type: text/x-patch, Size: 3896 bytes --]

From c593fc94f2289d4bdcb61835eaf11b0fe393a0f5 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Thu, 8 Dec 2022 21:05:10 +0100
Subject: [PATCH 1/2] Introduce 'compilation-aside' text property

It is meant to mark parts of compilation buffers which do not
correspond to process output.

* lisp/progmodes/compile.el (compilation-insert-aside):  New function.
(compilation-start, compilation-handle-exit): Use it.
(compilation--ensure-parse) Rely on 'compilation-aside' property
instead of 'compilation-header-end'
---
 lisp/progmodes/compile.el | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index e8ada9388e..2d22501017 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1675,7 +1675,7 @@ compilation--ensure-parse
             (set-marker (make-marker)
                         (save-excursion
                           (goto-char (point-min))
-                          (text-property-search-forward 'compilation-header-end)
+                          (text-property-search-forward 'compilation-aside)
                           ;; If we have no end marker, this will be
                           ;; `point-min' still.
                           (point)))))
@@ -1823,6 +1823,14 @@ compilation--update-in-progress-mode-line
   ;; buffers when it changes from nil to non-nil or vice-versa.
   (unless compilation-in-progress (force-mode-line-update t)))
 
+(defun compilation-insert-aside (&rest args)
+  "Insert ARGS at point, adding the `compilation-aside' text property.
+This property is used to distinguish output of the compilation
+process from additional information inserted by Emacs."
+  (let ((start (point)))
+    (apply #'insert args)
+    (put-text-property start (point) 'compilation-aside t)))
+
 ;;;###autoload
 (defun compilation-start (command &optional mode name-function highlight-regexp
                                   continue)
@@ -1944,17 +1952,16 @@ compilation-start
             (setq-local compilation-auto-jump-to-next t))
         (when (zerop (buffer-size))
 	  ;; Output a mode setter, for saving and later reloading this buffer.
-	  (insert "-*- mode: " name-of-mode
-		  "; default-directory: "
-                  (prin1-to-string (abbreviate-file-name default-directory))
-		  " -*-\n"))
-        (insert (format "%s started at %s\n\n"
-			mode-name
-			(substring (current-time-string) 0 19))
-		command "\n")
-        ;; Mark the end of the header so that we don't interpret
-        ;; anything in it as an error.
-        (put-text-property (1- (point)) (point) 'compilation-header-end t)
+	  (compilation-insert-aside
+           "-*- mode: " name-of-mode
+           "; default-directory: "
+           (prin1-to-string (abbreviate-file-name default-directory))
+	   " -*-\n"))
+        (compilation-insert-aside
+         (format "%s started at %s\n\n"
+                 mode-name
+		 (substring (current-time-string) 0 19))
+	 command "\n")
 	(setq thisdir default-directory))
       (set-buffer-modified-p nil))
     ;; Pop up the compilation buffer.
@@ -2436,13 +2443,13 @@ compilation-handle-exit
 	(cur-buffer (current-buffer)))
     ;; Record where we put the message, so we can ignore it later on.
     (goto-char omax)
-    (insert ?\n mode-name " " (car status))
+    (compilation-insert-aside ?\n mode-name " " (car status))
     (if (and (numberp compilation-window-height)
 	     (zerop compilation-window-height))
 	(message "%s" (cdr status)))
     (if (bolp)
 	(forward-char -1))
-    (insert " at " (substring (current-time-string) 0 19))
+    (compilation-insert-aside " at " (substring (current-time-string) 0 19))
     (goto-char (point-max))
     ;; Prevent that message from being recognized as a compilation error.
     (add-text-properties omax (point)
-- 
2.38.1


[-- Attachment #3: 0002-New-user-option-grep-use-headings.patch --]
[-- Type: text/x-patch, Size: 6324 bytes --]

From 549187135df21702210050e873210bd200612f96 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Wed, 7 Dec 2022 18:44:07 +0100
Subject: [PATCH 2/2] New user option 'grep-use-headings'

* lisp/progmodes/grep.el (grep-heading-regexp): New user option.
(grep-heading): New face.
(grep--heading-format, grep--heading-state, grep--heading-filter):
Filter function for grep processes and supporting variables.
(grep-use-headings): New user option.
(grep-mode): Use the above, if applicable.
---
 etc/NEWS                          |  8 ++++
 lisp/progmodes/grep.el            | 69 +++++++++++++++++++++++++++++++
 test/lisp/progmodes/grep-tests.el | 14 +++++++
 3 files changed, 91 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 3eeef0ab4c..4ad6e76687 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -41,6 +41,14 @@ connection.
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
+** Compile
+
+*** New user option 'grep-use-headings'.
+When non-nil, the grep output is split into sections, one for each
+file, instead of having file names prefixed to each line.  It is
+equivalent to the --heading option of some tools such as 'git grep'
+and 'rg.
+
 ** VC
 
 ---
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 2446e86abb..d6981c5951 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -30,6 +30,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'rx))
 (require 'compile)
 
 (defgroup grep nil
@@ -457,6 +458,35 @@ grep-search-path
   :type '(repeat (choice (const :tag "Default" nil)
 			 (string :tag "Directory"))))
 
+(defcustom grep-use-headings nil
+  "If non-nil, subdivide grep output into sections, one per file."
+  :type 'boolean
+  :version "30.1")
+
+(defcustom grep-heading-regexp
+  (rx bol
+      (or
+       (group-n 2
+         (group-n 1 (+ (not (any 0 ?\n))))
+         0)
+       (group-n 2
+        (group-n 1 (+? nonl))
+        (any ?: ?- ?=)))
+      (+ digit)
+      (any ?: ?- ?=))
+  "Regexp used to create headings from grep output lines.
+It should be anchored at beginning of line.  The first capture
+group, if present, should match the heading associated to the
+line.  The buffer range of the second capture, if present, is
+made invisible (presumably because displaying it would be
+redundant)."
+  :type 'regexp
+  :version "30.1")
+
+(defface grep-heading `((t :inherit ,grep-hit-face))
+  "Face of headings when using `grep-heading-mode'."
+  :version "30.1")
+
 (defvar grep-find-abbreviate-properties
   (let ((ellipsis (if (char-displayable-p ?…) "[…]" "[...]"))
         (map (make-sparse-keymap)))
@@ -612,6 +642,40 @@ grep-filter
         (while (re-search-forward "\033\\[[0-9;]*[mK]" end 1)
           (replace-match "" t t))))))
 
+(defvar grep--heading-format
+  (eval-when-compile
+    (let ((title (propertize "%s"
+                             'font-lock-face 'grep-heading
+                             'outline-level 1)))
+      (propertize (concat title "\n") 'compilation-aside t)))
+  "Format string of grep headings.
+This is passed to `format' with one argument, the text of the
+first capture group of `grep-heading-regexp'.")
+
+(defvar-local grep--heading-state nil
+  "Variable to keep track of the `grep--heading-filter' state.")
+
+(defun grep--heading-filter ()
+  "Filter function to add headings to output of a grep process."
+  (unless grep--heading-state
+    (setq grep--heading-state (cons (point-min-marker) nil)))
+  (save-excursion
+    (let ((limit (car grep--heading-state)))
+      ;; Move point to the old limit and update limit marker.
+      (move-marker limit (prog1 (pos-bol) (goto-char limit)))
+      (while (re-search-forward grep-heading-regexp limit t)
+        (unless (get-text-property (point) 'compilation-aside)
+          (let ((heading (match-string-no-properties 1))
+                (start (match-beginning 2))
+                (end (match-end 2)))
+            (when start
+              (put-text-property start end 'invisible t))
+            (when (and heading (not (equal heading (cdr grep--heading-state))))
+              (save-excursion
+                (forward-line 0)
+                (insert-before-markers (format grep--heading-format heading)))
+              (setf (cdr grep--heading-state) heading))))))))
+
 (defun grep-probe (command args &optional func result)
   (let (process-file-side-effects)
     (equal (condition-case nil
@@ -906,6 +970,11 @@ grep-mode
   (add-function :filter-return (local 'kill-transform-function)
                 (lambda (string)
                   (string-replace "\0" ":" string)))
+  (when grep-use-headings
+    (add-hook 'compilation-filter-hook #'grep--heading-filter 80 t)
+    (setq-local outline-search-function #'outline-search-level
+                outline-level (lambda () (get-text-property
+                                          (point) 'outline-level))))
   (add-hook 'compilation-filter-hook #'grep-filter nil t))
 
 (defun grep--save-buffers ()
diff --git a/test/lisp/progmodes/grep-tests.el b/test/lisp/progmodes/grep-tests.el
index 101052c5ad..51f4606639 100644
--- a/test/lisp/progmodes/grep-tests.el
+++ b/test/lisp/progmodes/grep-tests.el
@@ -66,4 +66,18 @@ grep-tests--rgrep-abbreviate-properties-windows-nt-sh-semantics
     (cl-letf (((symbol-function 'w32-shell-dos-semantics) #'ignore))
       (grep-tests--check-rgrep-abbreviation))))
 
+(ert-deftest grep-tests--grep-heading-regexp-without-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "filename%c123%ctext" sep sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "filename"))
+      (should (equal (match-string 2 string) (format "filename%c" sep))))))
+
+(ert-deftest grep-tests--grep-heading-regexp-with-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "funny:0:filename%c123%ctext" 0 sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "funny:0:filename"))
+      (should (equal (match-string 2 string) "funny:0:filename\0")))))
+
 ;;; grep-tests.el ends here
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09 12:18       ` bug#59888: [PATCH] Add 'grep-use-headings' Augusto Stoffel
@ 2022-12-09 19:36         ` Eli Zaretskii
  2022-12-09 20:03           ` Augusto Stoffel
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2022-12-09 19:36 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: larsi, stefankangas, 59888, juri

> From: Augusto Stoffel <arstoffel@gmail.com>
> Cc: Stefan Kangas <stefankangas@gmail.com>,  59888@debbugs.gnu.org, Eli
>  Zaretskii <eliz@gnu.org>, Lars Ingebrigtsen <larsi@gnus.org>
> Date: Fri, 09 Dec 2022 13:18:02 +0100
> 
> As discussed before, I introduced a text property so that one can tell
> without guessing which parts of the compilation buffer are not coming
> from the external process.  This seems to supersede the
> 'compilation-header-end' property introduced by Lars in commit
> 07f748da43, so I replaced its uses by the new 'compilation-aside'
> property.  I could easily revert that, but it seemed reasonable to
> uniformize things in this case.

Thanks, but please find a better name for this property.  Something
like compilation-meta-data, perhaps?

> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -41,6 +41,14 @@ connection.
>  \f
>  * Changes in Specialized Modes and Packages in Emacs 30.1
>  
> +** Compile
> +
> +*** New user option 'grep-use-headings'.
> +When non-nil, the grep output is split into sections, one for each
                     ^^^^
"Grep", capitalized.  Or maybe even "the output of Grep".

> +file, instead of having file names prefixed to each line.  It is
> +equivalent to the --heading option of some tools such as 'git grep'
> +and 'rg.
       ^^^
'rg'





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09 19:36         ` Eli Zaretskii
@ 2022-12-09 20:03           ` Augusto Stoffel
  2022-12-09 20:29             ` Eli Zaretskii
                               ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-09 20:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, stefankangas, 59888, juri

On Fri,  9 Dec 2022 at 21:36, Eli Zaretskii wrote:

>> As discussed before, I introduced a text property so that one can tell
>> without guessing which parts of the compilation buffer are not coming
>> from the external process.  This seems to supersede the
>> 'compilation-header-end' property introduced by Lars in commit
>> 07f748da43, so I replaced its uses by the new 'compilation-aside'
>> property.  I could easily revert that, but it seemed reasonable to
>> uniformize things in this case.
>
> Thanks, but please find a better name for this property.  Something
> like compilation-meta-data, perhaps?

All right, but since it's just a t-or-nil marking, I don't think
metadata is a very good description.  I considered 'compilation-info'
but that seems related to compiler warnings and errors.

I was looking for something that generally describes headers and
footers, prefaces and epilogues, etc., but I'm missing a good word for
that.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09 20:03           ` Augusto Stoffel
@ 2022-12-09 20:29             ` Eli Zaretskii
  2022-12-10 20:08               ` Augusto Stoffel
  2022-12-09 20:40             ` Gregory Heytings
  2022-12-10 17:24             ` Juri Linkov
  2 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2022-12-09 20:29 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: larsi, stefankangas, 59888, juri

> From: Augusto Stoffel <arstoffel@gmail.com>
> Cc: juri@linkov.net,  stefankangas@gmail.com,  59888@debbugs.gnu.org,
>   larsi@gnus.org
> Date: Fri, 09 Dec 2022 21:03:17 +0100
> 
> > Thanks, but please find a better name for this property.  Something
> > like compilation-meta-data, perhaps?
> 
> All right, but since it's just a t-or-nil marking, I don't think
> metadata is a very good description.  I considered 'compilation-info'
> but that seems related to compiler warnings and errors.

How about 'compilation-details'?

> I was looking for something that generally describes headers and
> footers, prefaces and epilogues, etc., but I'm missing a good word for
> that.

If "details" doesn't fit the bill, how about "decorations"?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09 20:03           ` Augusto Stoffel
  2022-12-09 20:29             ` Eli Zaretskii
@ 2022-12-09 20:40             ` Gregory Heytings
  2022-12-10 17:24             ` Juri Linkov
  2 siblings, 0 replies; 37+ messages in thread
From: Gregory Heytings @ 2022-12-09 20:40 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Eli Zaretskii, juri, larsi, 59888, stefankangas


>
> I was looking for something that generally describes headers and 
> footers, prefaces and epilogues, etc., but I'm missing a good word for 
> that.
>

Decorations?  Frills?






^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09 20:03           ` Augusto Stoffel
  2022-12-09 20:29             ` Eli Zaretskii
  2022-12-09 20:40             ` Gregory Heytings
@ 2022-12-10 17:24             ` Juri Linkov
  2 siblings, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2022-12-10 17:24 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: larsi, Eli Zaretskii, stefankangas, 59888

> I was looking for something that generally describes headers and
> footers, prefaces and epilogues, etc., but I'm missing a good word for
> that.

This suggests "marginals":
https://english.stackexchange.com/questions/24060/what-word-defines-a-category-suited-for-both-header-and-footer





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-09 20:29             ` Eli Zaretskii
@ 2022-12-10 20:08               ` Augusto Stoffel
  2022-12-10 20:16                 ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-10 20:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: larsi, stefankangas, 59888, juri

On Fri,  9 Dec 2022 at 22:29, Eli Zaretskii wrote:

>> From: Augusto Stoffel <arstoffel@gmail.com>
>> Cc: juri@linkov.net,  stefankangas@gmail.com,  59888@debbugs.gnu.org,
>>   larsi@gnus.org
>> Date: Fri, 09 Dec 2022 21:03:17 +0100
>> 
>> > Thanks, but please find a better name for this property.  Something
>> > like compilation-meta-data, perhaps?
>> 
>> All right, but since it's just a t-or-nil marking, I don't think
>> metadata is a very good description.  I considered 'compilation-info'
>> but that seems related to compiler warnings and errors.
>
> How about 'compilation-details'?
>
>> I was looking for something that generally describes headers and
>> footers, prefaces and epilogues, etc., but I'm missing a good word for
>> that.
>
> If "details" doesn't fit the bill, how about "decorations"?

Would you be okay with 'compilation-annotation'?  "Decoration" sounds
good, but I like "annotation" slightly better.

Thanks for all the suggestions.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-10 20:08               ` Augusto Stoffel
@ 2022-12-10 20:16                 ` Eli Zaretskii
  2022-12-11 11:30                   ` Augusto Stoffel
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2022-12-10 20:16 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: larsi, stefankangas, 59888, juri

> From: Augusto Stoffel <arstoffel@gmail.com>
> Cc: juri@linkov.net,  stefankangas@gmail.com,  59888@debbugs.gnu.org,
>   larsi@gnus.org
> Date: Sat, 10 Dec 2022 21:08:05 +0100
> 
> On Fri,  9 Dec 2022 at 22:29, Eli Zaretskii wrote:
> 
> >> From: Augusto Stoffel <arstoffel@gmail.com>
> >> Cc: juri@linkov.net,  stefankangas@gmail.com,  59888@debbugs.gnu.org,
> >>   larsi@gnus.org
> >> Date: Fri, 09 Dec 2022 21:03:17 +0100
> >> 
> >> > Thanks, but please find a better name for this property.  Something
> >> > like compilation-meta-data, perhaps?
> >> 
> >> All right, but since it's just a t-or-nil marking, I don't think
> >> metadata is a very good description.  I considered 'compilation-info'
> >> but that seems related to compiler warnings and errors.
> >
> > How about 'compilation-details'?
> >
> >> I was looking for something that generally describes headers and
> >> footers, prefaces and epilogues, etc., but I'm missing a good word for
> >> that.
> >
> > If "details" doesn't fit the bill, how about "decorations"?
> 
> Would you be okay with 'compilation-annotation'?  "Decoration" sounds
> good, but I like "annotation" slightly better.

Could be.  Or how about compilation-aux-data?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-10 20:16                 ` Eli Zaretskii
@ 2022-12-11 11:30                   ` Augusto Stoffel
  2022-12-15  8:05                     ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2022-12-11 11:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: stefankangas, 59888, juri

[-- Attachment #1: Type: text/plain, Size: 80 bytes --]

I've attached a new version of the patch incorporating the latest
discussions.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Introduce-compilation-annotation-text-property.patch --]
[-- Type: text/x-patch, Size: 3951 bytes --]

From 8aa2bebbe1b12094963fdeb3251f3ef3c22ea5e9 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Thu, 8 Dec 2022 21:05:10 +0100
Subject: [PATCH 1/2] Introduce 'compilation-annotation' text property

It is meant to mark parts of compilation buffers which do not
correspond to process output.

* lisp/progmodes/compile.el (compilation-insert-annotation): New
function.
(compilation-start, compilation-handle-exit): Use it.
(compilation--ensure-parse) Rely on 'compilation-annotation' property
instead of 'compilation-header-end'.
---
 lisp/progmodes/compile.el | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index e8ada9388e..3aa6867533 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1675,7 +1675,7 @@ compilation--ensure-parse
             (set-marker (make-marker)
                         (save-excursion
                           (goto-char (point-min))
-                          (text-property-search-forward 'compilation-header-end)
+                          (text-property-search-forward 'compilation-annotation)
                           ;; If we have no end marker, this will be
                           ;; `point-min' still.
                           (point)))))
@@ -1823,6 +1823,14 @@ compilation--update-in-progress-mode-line
   ;; buffers when it changes from nil to non-nil or vice-versa.
   (unless compilation-in-progress (force-mode-line-update t)))
 
+(defun compilation-insert-annotation (&rest args)
+  "Insert ARGS at point, adding the `compilation-annotation' text property.
+This property is used to distinguish output of the compilation
+process from additional information inserted by Emacs."
+  (let ((start (point)))
+    (apply #'insert args)
+    (put-text-property start (point) 'compilation-annotation t)))
+
 ;;;###autoload
 (defun compilation-start (command &optional mode name-function highlight-regexp
                                   continue)
@@ -1944,17 +1952,16 @@ compilation-start
             (setq-local compilation-auto-jump-to-next t))
         (when (zerop (buffer-size))
 	  ;; Output a mode setter, for saving and later reloading this buffer.
-	  (insert "-*- mode: " name-of-mode
-		  "; default-directory: "
-                  (prin1-to-string (abbreviate-file-name default-directory))
-		  " -*-\n"))
-        (insert (format "%s started at %s\n\n"
-			mode-name
-			(substring (current-time-string) 0 19))
-		command "\n")
-        ;; Mark the end of the header so that we don't interpret
-        ;; anything in it as an error.
-        (put-text-property (1- (point)) (point) 'compilation-header-end t)
+	  (compilation-insert-annotation
+           "-*- mode: " name-of-mode
+           "; default-directory: "
+           (prin1-to-string (abbreviate-file-name default-directory))
+	   " -*-\n"))
+        (compilation-insert-annotation
+         (format "%s started at %s\n\n"
+                 mode-name
+		 (substring (current-time-string) 0 19))
+	 command "\n")
 	(setq thisdir default-directory))
       (set-buffer-modified-p nil))
     ;; Pop up the compilation buffer.
@@ -2436,13 +2443,13 @@ compilation-handle-exit
 	(cur-buffer (current-buffer)))
     ;; Record where we put the message, so we can ignore it later on.
     (goto-char omax)
-    (insert ?\n mode-name " " (car status))
+    (compilation-insert-annotation ?\n mode-name " " (car status))
     (if (and (numberp compilation-window-height)
 	     (zerop compilation-window-height))
 	(message "%s" (cdr status)))
     (if (bolp)
 	(forward-char -1))
-    (insert " at " (substring (current-time-string) 0 19))
+    (compilation-insert-annotation " at " (substring (current-time-string) 0 19))
     (goto-char (point-max))
     ;; Prevent that message from being recognized as a compilation error.
     (add-text-properties omax (point)
-- 
2.38.1


[-- Attachment #3: 0002-New-user-option-grep-use-headings.patch --]
[-- Type: text/x-patch, Size: 6338 bytes --]

From e1209a93e09792cbb61bde9ae3ac8838c76861a5 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Wed, 7 Dec 2022 18:44:07 +0100
Subject: [PATCH 2/2] New user option 'grep-use-headings'

* lisp/progmodes/grep.el (grep-heading-regexp): New user option.
(grep-heading): New face.
(grep--heading-format, grep--heading-state, grep--heading-filter):
Filter function for grep processes and supporting variables.
(grep-use-headings): New user option.
(grep-mode): Use the above, if applicable.
---
 etc/NEWS                          |  8 ++++
 lisp/progmodes/grep.el            | 69 +++++++++++++++++++++++++++++++
 test/lisp/progmodes/grep-tests.el | 14 +++++++
 3 files changed, 91 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 3eeef0ab4c..ac5ed7cbf3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -41,6 +41,14 @@ connection.
 \f
 * Changes in Specialized Modes and Packages in Emacs 30.1
 
+** Compile
+
+*** New user option 'grep-use-headings'.
+When non-nil, the output of Grep is split into sections, one for each
+file, instead of having file names prefixed to each line.  It is
+equivalent to the --heading option of some tools such as 'git grep'
+and 'rg'.
+
 ** VC
 
 ---
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 2446e86abb..c6be39fbb7 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -30,6 +30,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'rx))
 (require 'compile)
 
 (defgroup grep nil
@@ -457,6 +458,35 @@ grep-search-path
   :type '(repeat (choice (const :tag "Default" nil)
 			 (string :tag "Directory"))))
 
+(defcustom grep-use-headings nil
+  "If non-nil, subdivide grep output into sections, one per file."
+  :type 'boolean
+  :version "30.1")
+
+(defcustom grep-heading-regexp
+  (rx bol
+      (or
+       (group-n 2
+         (group-n 1 (+ (not (any 0 ?\n))))
+         0)
+       (group-n 2
+        (group-n 1 (+? nonl))
+        (any ?: ?- ?=)))
+      (+ digit)
+      (any ?: ?- ?=))
+  "Regexp used to create headings from grep output lines.
+It should be anchored at beginning of line.  The first capture
+group, if present, should match the heading associated to the
+line.  The buffer range of the second capture, if present, is
+made invisible (presumably because displaying it would be
+redundant)."
+  :type 'regexp
+  :version "30.1")
+
+(defface grep-heading `((t :inherit ,grep-hit-face))
+  "Face of headings when using `grep-heading-mode'."
+  :version "30.1")
+
 (defvar grep-find-abbreviate-properties
   (let ((ellipsis (if (char-displayable-p ?…) "[…]" "[...]"))
         (map (make-sparse-keymap)))
@@ -612,6 +642,40 @@ grep-filter
         (while (re-search-forward "\033\\[[0-9;]*[mK]" end 1)
           (replace-match "" t t))))))
 
+(defvar grep--heading-format
+  (eval-when-compile
+    (let ((title (propertize "%s"
+                             'font-lock-face 'grep-heading
+                             'outline-level 1)))
+      (propertize (concat title "\n") 'compilation-annotation t)))
+  "Format string of grep headings.
+This is passed to `format' with one argument, the text of the
+first capture group of `grep-heading-regexp'.")
+
+(defvar-local grep--heading-state nil
+  "Variable to keep track of the `grep--heading-filter' state.")
+
+(defun grep--heading-filter ()
+  "Filter function to add headings to output of a grep process."
+  (unless grep--heading-state
+    (setq grep--heading-state (cons (point-min-marker) nil)))
+  (save-excursion
+    (let ((limit (car grep--heading-state)))
+      ;; Move point to the old limit and update limit marker.
+      (move-marker limit (prog1 (pos-bol) (goto-char limit)))
+      (while (re-search-forward grep-heading-regexp limit t)
+        (unless (get-text-property (point) 'compilation-annotation)
+          (let ((heading (match-string-no-properties 1))
+                (start (match-beginning 2))
+                (end (match-end 2)))
+            (when start
+              (put-text-property start end 'invisible t))
+            (when (and heading (not (equal heading (cdr grep--heading-state))))
+              (save-excursion
+                (forward-line 0)
+                (insert-before-markers (format grep--heading-format heading)))
+              (setf (cdr grep--heading-state) heading))))))))
+
 (defun grep-probe (command args &optional func result)
   (let (process-file-side-effects)
     (equal (condition-case nil
@@ -906,6 +970,11 @@ grep-mode
   (add-function :filter-return (local 'kill-transform-function)
                 (lambda (string)
                   (string-replace "\0" ":" string)))
+  (when grep-use-headings
+    (add-hook 'compilation-filter-hook #'grep--heading-filter 80 t)
+    (setq-local outline-search-function #'outline-search-level
+                outline-level (lambda () (get-text-property
+                                          (point) 'outline-level))))
   (add-hook 'compilation-filter-hook #'grep-filter nil t))
 
 (defun grep--save-buffers ()
diff --git a/test/lisp/progmodes/grep-tests.el b/test/lisp/progmodes/grep-tests.el
index 101052c5ad..51f4606639 100644
--- a/test/lisp/progmodes/grep-tests.el
+++ b/test/lisp/progmodes/grep-tests.el
@@ -66,4 +66,18 @@ grep-tests--rgrep-abbreviate-properties-windows-nt-sh-semantics
     (cl-letf (((symbol-function 'w32-shell-dos-semantics) #'ignore))
       (grep-tests--check-rgrep-abbreviation))))
 
+(ert-deftest grep-tests--grep-heading-regexp-without-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "filename%c123%ctext" sep sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "filename"))
+      (should (equal (match-string 2 string) (format "filename%c" sep))))))
+
+(ert-deftest grep-tests--grep-heading-regexp-with-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "funny:0:filename%c123%ctext" 0 sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "funny:0:filename"))
+      (should (equal (match-string 2 string) "funny:0:filename\0")))))
+
 ;;; grep-tests.el ends here
-- 
2.38.1


[-- Attachment #4: Type: text/plain, Size: 535 bytes --]


There is still an issue I'm aware of: if one saves a grep buffer to a
file and later opens the file, the headings are inserted a second time.
I've tried a bit to display the headings only using text display
properties (instead of inserting the actual text into the buffer), but
wasn't successful so far.  Other, less elegant solutions are possible
(e.g. deleting all headings either when saving or when reading again the
file).

We could install this change now and polish it later or continue this
discussion -- both are fine by me.

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-11 11:30                   ` Augusto Stoffel
@ 2022-12-15  8:05                     ` Juri Linkov
  2023-02-25  8:34                       ` Augusto Stoffel
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2022-12-15  8:05 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Eli Zaretskii, stefankangas, 59888

> There is still an issue I'm aware of: if one saves a grep buffer to a
> file and later opens the file, the headings are inserted a second time.
> I've tried a bit to display the headings only using text display
> properties (instead of inserting the actual text into the buffer), but
> wasn't successful so far.  Other, less elegant solutions are possible
> (e.g. deleting all headings either when saving or when reading again the
> file).

This reminds a similar problem that the file etc/grep.txt
can't be edited in grep-mode because then it will lose
all grep-filtered escape sequences on saving.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2022-12-15  8:05                     ` Juri Linkov
@ 2023-02-25  8:34                       ` Augusto Stoffel
  2023-02-25 18:00                         ` Juri Linkov
  2023-02-26 13:17                         ` Robert Pluim
  0 siblings, 2 replies; 37+ messages in thread
From: Augusto Stoffel @ 2023-02-25  8:34 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Eli Zaretskii, stefankangas, 59888

[-- Attachment #1: Type: text/plain, Size: 120 bytes --]

I've been using the grep-use-headings locally for a long time and it
works well.  Should the the patches be installed?


[-- Attachment #2: 0002-New-user-option-grep-use-headings.patch --]
[-- Type: text/x-patch, Size: 6464 bytes --]

From 77ea46f6dc50a8f463bd2f51ce9d0585de0bb55c Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Wed, 7 Dec 2022 18:44:07 +0100
Subject: [PATCH 2/2] New user option 'grep-use-headings'

* lisp/progmodes/grep.el (grep-heading-regexp): New user option.
(grep-heading): New face.
(grep--heading-format, grep--heading-state, grep--heading-filter):
Filter function for grep processes and supporting variables.
(grep-use-headings): New user option.
(grep-mode): Use the above, if applicable.
---
 etc/NEWS                          |  8 ++++
 lisp/progmodes/grep.el            | 69 +++++++++++++++++++++++++++++++
 test/lisp/progmodes/grep-tests.el | 14 +++++++
 3 files changed, 91 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 4b0e4e6bd46..ca2e8011510 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -95,6 +95,14 @@ If you want to get back the old behavior, set the user option to the value
     (setopt gdb-locals-table-row-config
             `((type . 0) (name . 0) (value . ,gdb-locals-value-limit)))
 
+** Compile
+
+*** New user option 'grep-use-headings'.
+When non-nil, the output of Grep is split into sections, one for each
+file, instead of having file names prefixed to each line.  It is
+equivalent to the --heading option of some tools such as 'git grep'
+and 'rg'.
+
 ** VC
 
 ---
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 0da16b44dda..9e3cec89c01 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -30,6 +30,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'rx))
 (require 'compile)
 
 (defgroup grep nil
@@ -457,6 +458,35 @@ grep-search-path
   :type '(repeat (choice (const :tag "Default" nil)
 			 (string :tag "Directory"))))
 
+(defcustom grep-use-headings nil
+  "If non-nil, subdivide grep output into sections, one per file."
+  :type 'boolean
+  :version "30.1")
+
+(defcustom grep-heading-regexp
+  (rx bol
+      (or
+       (group-n 2
+         (group-n 1 (+ (not (any 0 ?\n))))
+         0)
+       (group-n 2
+        (group-n 1 (+? nonl))
+        (any ?: ?- ?=)))
+      (+ digit)
+      (any ?: ?- ?=))
+  "Regexp used to create headings from grep output lines.
+It should be anchored at beginning of line.  The first capture
+group, if present, should match the heading associated to the
+line.  The buffer range of the second capture, if present, is
+made invisible (presumably because displaying it would be
+redundant)."
+  :type 'regexp
+  :version "30.1")
+
+(defface grep-heading `((t :inherit ,grep-hit-face))
+  "Face of headings when `grep-use-headings' is non-nil."
+  :version "30.1")
+
 (defvar grep-find-abbreviate-properties
   (let ((ellipsis (if (char-displayable-p ?…) "[…]" "[...]"))
         (map (make-sparse-keymap)))
@@ -612,6 +642,40 @@ grep-filter
         (while (re-search-forward "\033\\[[0-9;]*[mK]" end 1)
           (replace-match "" t t))))))
 
+(defvar grep--heading-format
+  (eval-when-compile
+    (let ((title (propertize "%s"
+                             'font-lock-face 'grep-heading
+                             'outline-level 1)))
+      (propertize (concat title "\n") 'compilation-annotation t)))
+  "Format string of grep headings.
+This is passed to `format' with one argument, the text of the
+first capture group of `grep-heading-regexp'.")
+
+(defvar-local grep--heading-state nil
+  "Variable to keep track of the `grep--heading-filter' state.")
+
+(defun grep--heading-filter ()
+  "Filter function to add headings to output of a grep process."
+  (unless grep--heading-state
+    (setq grep--heading-state (cons (point-min-marker) nil)))
+  (save-excursion
+    (let ((limit (car grep--heading-state)))
+      ;; Move point to the old limit and update limit marker.
+      (move-marker limit (prog1 (pos-bol) (goto-char limit)))
+      (while (re-search-forward grep-heading-regexp limit t)
+        (unless (get-text-property (point) 'compilation-annotation)
+          (let ((heading (match-string-no-properties 1))
+                (start (match-beginning 2))
+                (end (match-end 2)))
+            (when start
+              (put-text-property start end 'invisible t))
+            (when (and heading (not (equal heading (cdr grep--heading-state))))
+              (save-excursion
+                (forward-line 0)
+                (insert-before-markers (format grep--heading-format heading)))
+              (setf (cdr grep--heading-state) heading))))))))
+
 (defun grep-probe (command args &optional func result)
   (let (process-file-side-effects)
     (equal (condition-case nil
@@ -906,6 +970,11 @@ grep-mode
   (add-function :filter-return (local 'kill-transform-function)
                 (lambda (string)
                   (string-replace "\0" ":" string)))
+  (when grep-use-headings
+    (add-hook 'compilation-filter-hook #'grep--heading-filter 80 t)
+    (setq-local outline-search-function #'outline-search-level
+                outline-level (lambda () (get-text-property
+                                          (point) 'outline-level))))
   (add-hook 'compilation-filter-hook #'grep-filter nil t))
 
 (defun grep--save-buffers ()
diff --git a/test/lisp/progmodes/grep-tests.el b/test/lisp/progmodes/grep-tests.el
index 39307999d6d..9b7f83086bf 100644
--- a/test/lisp/progmodes/grep-tests.el
+++ b/test/lisp/progmodes/grep-tests.el
@@ -66,4 +66,18 @@ grep-tests--rgrep-abbreviate-properties-windows-nt-sh-semantics
     (cl-letf (((symbol-function 'w32-shell-dos-semantics) #'ignore))
       (grep-tests--check-rgrep-abbreviation))))
 
+(ert-deftest grep-tests--grep-heading-regexp-without-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "filename%c123%ctext" sep sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "filename"))
+      (should (equal (match-string 2 string) (format "filename%c" sep))))))
+
+(ert-deftest grep-tests--grep-heading-regexp-with-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "funny:0:filename%c123%ctext" 0 sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "funny:0:filename"))
+      (should (equal (match-string 2 string) "funny:0:filename\0")))))
+
 ;;; grep-tests.el ends here
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Introduce-compilation-annotation-text-property.patch --]
[-- Type: text/x-patch, Size: 3953 bytes --]

From 6d97ae3b43fe893f2ec7dab67c14f06e1eb9a3fb Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Thu, 8 Dec 2022 21:05:10 +0100
Subject: [PATCH 1/2] Introduce 'compilation-annotation' text property

It is meant to mark parts of compilation buffers which do not
correspond to process output.

* lisp/progmodes/compile.el (compilation-insert-annotation): New
function.
(compilation-start, compilation-handle-exit): Use it.
(compilation--ensure-parse) Rely on 'compilation-annotation' property
instead of 'compilation-header-end'.
---
 lisp/progmodes/compile.el | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index ccf64fb670b..6d151db8a83 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1706,7 +1706,7 @@ compilation--ensure-parse
             (set-marker (make-marker)
                         (save-excursion
                           (goto-char (point-min))
-                          (text-property-search-forward 'compilation-header-end)
+                          (text-property-search-forward 'compilation-annotation)
                           ;; If we have no end marker, this will be
                           ;; `point-min' still.
                           (point)))))
@@ -1854,6 +1854,14 @@ compilation--update-in-progress-mode-line
   ;; buffers when it changes from nil to non-nil or vice-versa.
   (unless compilation-in-progress (force-mode-line-update t)))
 
+(defun compilation-insert-annotation (&rest args)
+  "Insert ARGS at point, adding the `compilation-annotation' text property.
+This property is used to distinguish output of the compilation
+process from additional information inserted by Emacs."
+  (let ((start (point)))
+    (apply #'insert args)
+    (put-text-property start (point) 'compilation-annotation t)))
+
 ;;;###autoload
 (defun compilation-start (command &optional mode name-function highlight-regexp
                                   continue)
@@ -1975,17 +1983,16 @@ compilation-start
             (setq-local compilation-auto-jump-to-next t))
         (when (zerop (buffer-size))
 	  ;; Output a mode setter, for saving and later reloading this buffer.
-	  (insert "-*- mode: " name-of-mode
-		  "; default-directory: "
-                  (prin1-to-string (abbreviate-file-name default-directory))
-		  " -*-\n"))
-        (insert (format "%s started at %s\n\n"
-			mode-name
-			(substring (current-time-string) 0 19))
-		command "\n")
-        ;; Mark the end of the header so that we don't interpret
-        ;; anything in it as an error.
-        (put-text-property (1- (point)) (point) 'compilation-header-end t)
+	  (compilation-insert-annotation
+           "-*- mode: " name-of-mode
+           "; default-directory: "
+           (prin1-to-string (abbreviate-file-name default-directory))
+	   " -*-\n"))
+        (compilation-insert-annotation
+         (format "%s started at %s\n\n"
+                 mode-name
+		 (substring (current-time-string) 0 19))
+	 command "\n")
 	(setq thisdir default-directory))
       (set-buffer-modified-p nil))
     ;; Pop up the compilation buffer.
@@ -2467,13 +2474,13 @@ compilation-handle-exit
 	(cur-buffer (current-buffer)))
     ;; Record where we put the message, so we can ignore it later on.
     (goto-char omax)
-    (insert ?\n mode-name " " (car status))
+    (compilation-insert-annotation ?\n mode-name " " (car status))
     (if (and (numberp compilation-window-height)
 	     (zerop compilation-window-height))
 	(message "%s" (cdr status)))
     (if (bolp)
 	(forward-char -1))
-    (insert " at " (substring (current-time-string) 0 19))
+    (compilation-insert-annotation " at " (substring (current-time-string) 0 19))
     (goto-char (point-max))
     ;; Prevent that message from being recognized as a compilation error.
     (add-text-properties omax (point)
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-25  8:34                       ` Augusto Stoffel
@ 2023-02-25 18:00                         ` Juri Linkov
  2023-02-26 13:17                         ` Robert Pluim
  1 sibling, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2023-02-25 18:00 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Eli Zaretskii, stefankangas, 59888

> I've been using the grep-use-headings locally for a long time and it
> works well.  Should the the patches be installed?

Thanks, I'd like to try out your patches for a few days.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-25  8:34                       ` Augusto Stoffel
  2023-02-25 18:00                         ` Juri Linkov
@ 2023-02-26 13:17                         ` Robert Pluim
  2023-02-26 15:07                           ` Augusto Stoffel
  1 sibling, 1 reply; 37+ messages in thread
From: Robert Pluim @ 2023-02-26 13:17 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Eli Zaretskii, stefankangas, 59888, Juri Linkov

>>>>> On Sat, 25 Feb 2023 09:34:56 +0100, Augusto Stoffel <arstoffel@gmail.com> said:

    Augusto> I've been using the grep-use-headings locally for a long time and it
    Augusto> works well.  Should the the patches be installed?

    Augusto> From 77ea46f6dc50a8f463bd2f51ce9d0585de0bb55c Mon Sep 17 00:00:00 2001
    Augusto> From: Augusto Stoffel <arstoffel@gmail.com>
    Augusto> Date: Wed, 7 Dec 2022 18:44:07 +0100
    Augusto> Subject: [PATCH 2/2] New user option 'grep-use-headings'

    Augusto> * lisp/progmodes/grep.el (grep-heading-regexp): New user option.
    Augusto> (grep-heading): New face.
    Augusto> (grep--heading-format, grep--heading-state, grep--heading-filter):
    Augusto> Filter function for grep processes and supporting variables.
    Augusto> (grep-use-headings): New user option.
    Augusto> (grep-mode): Use the above, if applicable.
    Augusto> ---
    Augusto>  etc/NEWS                          |  8 ++++
    Augusto>  lisp/progmodes/grep.el            | 69 +++++++++++++++++++++++++++++++
    Augusto>  test/lisp/progmodes/grep-tests.el | 14 +++++++
    Augusto>  3 files changed, 91 insertions(+)

    Augusto> diff --git a/etc/NEWS b/etc/NEWS
    Augusto> index 4b0e4e6bd46..ca2e8011510 100644
    Augusto> --- a/etc/NEWS
    Augusto> +++ b/etc/NEWS
    Augusto> @@ -95,6 +95,14 @@ If you want to get back the old behavior, set the user option to the value
    Augusto>      (setopt gdb-locals-table-row-config
    Augusto>              `((type . 0) (name . 0) (value . ,gdb-locals-value-limit)))
 
    Augusto> +** Compile
    Augusto> +
    Augusto> +*** New user option 'grep-use-headings'.
    Augusto> +When non-nil, the output of Grep is split into sections, one for each
    Augusto> +file, instead of having file names prefixed to each line.  It is
    Augusto> +equivalent to the --heading option of some tools such as 'git grep'
    Augusto> +and 'rg'.
    Augusto> +

You also add a face and a user option for the regexp, they should be
mentioned in NEWS (and the manual, if relevant)
 
    Augusto> +(defvar grep--heading-format
    Augusto> +  (eval-when-compile
    Augusto> +    (let ((title (propertize "%s"
    Augusto> +                             'font-lock-face 'grep-heading
    Augusto> +                             'outline-level 1)))
    Augusto> +      (propertize (concat title "\n") 'compilation-annotation t)))
    Augusto> +  "Format string of grep headings.
    Augusto> +This is passed to `format' with one argument, the text of the
    Augusto> +first capture group of `grep-heading-regexp'.")
    Augusto> +
    Augusto> +(defvar-local grep--heading-state nil
    Augusto> +  "Variable to keep track of the `grep--heading-filter' state.")
    Augusto> +
    Augusto> +(defun grep--heading-filter ()
    Augusto> +  "Filter function to add headings to output of a grep process."
    Augusto> +  (unless grep--heading-state
    Augusto> +    (setq grep--heading-state (cons (point-min-marker) nil)))
    Augusto> +  (save-excursion
    Augusto> +    (let ((limit (car grep--heading-state)))
    Augusto> +      ;; Move point to the old limit and update limit marker.
    Augusto> +      (move-marker limit (prog1 (pos-bol) (goto-char limit)))
    Augusto> +      (while (re-search-forward grep-heading-regexp limit t)
    Augusto> +        (unless (get-text-property (point) 'compilation-annotation)
    Augusto> +          (let ((heading (match-string-no-properties 1))
    Augusto> +                (start (match-beginning 2))
    Augusto> +                (end (match-end 2)))
    Augusto> +            (when start
    Augusto> +              (put-text-property start end 'invisible t))
    Augusto> +            (when (and heading (not (equal heading (cdr grep--heading-state))))
    Augusto> +              (save-excursion
    Augusto> +                (forward-line 0)

Thatʼs the same as (goto-char (pos-bol)) because of a wrinkle in the
implementation of `forward-line'.  It might even be faster, but Iʼve
not measured it :-)

Robert
-- 





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-26 13:17                         ` Robert Pluim
@ 2023-02-26 15:07                           ` Augusto Stoffel
  2023-02-27  6:24                             ` Robert Pluim
  2023-02-27 18:53                             ` Juri Linkov
  0 siblings, 2 replies; 37+ messages in thread
From: Augusto Stoffel @ 2023-02-26 15:07 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Eli Zaretskii, stefankangas, 59888, Juri Linkov

On Sun, 26 Feb 2023 at 14:17, Robert Pluim wrote:

> You also add a face and a user option for the regexp, they should be
> mentioned in NEWS (and the manual, if relevant)

Thanks, I added the face to the NEWS (but not the regexp, which is not a
user option although it can be modified if you are desperate).

>     Augusto> +                (forward-line 0)
>
> Thatʼs the same as (goto-char (pos-bol)) because of a wrinkle in the
> implementation of `forward-line'.  It might even be faster, but Iʼve
> not measured it :-)

Ugh, that was an anachronism.  It will be fixed when I send the final
patch.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-26 15:07                           ` Augusto Stoffel
@ 2023-02-27  6:24                             ` Robert Pluim
  2023-02-27 11:26                               ` Augusto Stoffel
  2023-02-27 18:53                             ` Juri Linkov
  1 sibling, 1 reply; 37+ messages in thread
From: Robert Pluim @ 2023-02-27  6:24 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Eli Zaretskii, Juri Linkov, stefankangas, 59888

>>>>> On Sun, 26 Feb 2023 16:07:13 +0100, Augusto Stoffel <arstoffel@gmail.com> said:

    Augusto> On Sun, 26 Feb 2023 at 14:17, Robert Pluim wrote:
    >> You also add a face and a user option for the regexp, they should be
    >> mentioned in NEWS (and the manual, if relevant)

    Augusto> Thanks, I added the face to the NEWS (but not the regexp, which is not a
    Augusto> user option although it can be modified if you are desperate).

Itʼs a `defcustom', so by definition itʼs a user option. If youʼre not
expecting it to be modified, maybe make it a `defvar'.

Robert
-- 





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-27  6:24                             ` Robert Pluim
@ 2023-02-27 11:26                               ` Augusto Stoffel
  2023-02-27 16:51                                 ` Robert Pluim
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2023-02-27 11:26 UTC (permalink / raw)
  To: Robert Pluim; +Cc: Eli Zaretskii, Juri Linkov, stefankangas, 59888

On Mon, 27 Feb 2023 at 07:24, Robert Pluim wrote:

> Itʼs a `defcustom', so by definition itʼs a user option. If youʼre not
> expecting it to be modified, maybe make it a `defvar'.

Oops, I wrote this a couple months back and had forgotten.

I don't know if you have an opinion.  `grep-regexp-alist' is a defconst,
which seems exaggerated, but `grep-match-regexp' is a defcustom although
nobody should want to change this except to work around bugs.

My new variable has a similar "degree of technicality" and I think that
asks for be a defvar.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-heading-mode'
  2022-12-08 10:48     ` Mattias Engdegård
@ 2023-02-27 14:18       ` Mattias Engdegård
  0 siblings, 0 replies; 37+ messages in thread
From: Mattias Engdegård @ 2023-02-27 14:18 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

> +(eval-when-compile (require 'rx))

Is this needed? The `rx` macro is autoloaded.






^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-27 11:26                               ` Augusto Stoffel
@ 2023-02-27 16:51                                 ` Robert Pluim
  0 siblings, 0 replies; 37+ messages in thread
From: Robert Pluim @ 2023-02-27 16:51 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Eli Zaretskii, stefankangas, 59888, Juri Linkov

>>>>> On Mon, 27 Feb 2023 12:26:08 +0100, Augusto Stoffel <arstoffel@gmail.com> said:

    Augusto> On Mon, 27 Feb 2023 at 07:24, Robert Pluim wrote:
    >> Itʼs a `defcustom', so by definition itʼs a user option. If youʼre not
    >> expecting it to be modified, maybe make it a `defvar'.

    Augusto> Oops, I wrote this a couple months back and had forgotten.

    Augusto> I don't know if you have an opinion.  `grep-regexp-alist' is a defconst,
    Augusto> which seems exaggerated, but `grep-match-regexp' is a defcustom although
    Augusto> nobody should want to change this except to work around bugs.

    Augusto> My new variable has a similar "degree of technicality" and I think that
    Augusto> asks for be a defvar.

I think I agree.

Robert
-- 





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-26 15:07                           ` Augusto Stoffel
  2023-02-27  6:24                             ` Robert Pluim
@ 2023-02-27 18:53                             ` Juri Linkov
  2023-02-27 19:06                               ` Augusto Stoffel
  1 sibling, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2023-02-27 18:53 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Robert Pluim, Eli Zaretskii, 59888, stefankangas

>> Thatʼs the same as (goto-char (pos-bol)) because of a wrinkle in the
>> implementation of `forward-line'.  It might even be faster, but Iʼve
>> not measured it :-)
>
> Ugh, that was an anachronism.  It will be fixed when I send the final
> patch.

I tried out your patch, and everything works nicely.
So I guess it could be pushed when you send the final version.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-27 18:53                             ` Juri Linkov
@ 2023-02-27 19:06                               ` Augusto Stoffel
  2023-02-27 19:15                                 ` Juri Linkov
  2023-02-28 17:24                                 ` Juri Linkov
  0 siblings, 2 replies; 37+ messages in thread
From: Augusto Stoffel @ 2023-02-27 19:06 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Robert Pluim, Eli Zaretskii, 59888, stefankangas

[-- Attachment #1: Type: text/plain, Size: 189 bytes --]

On Mon, 27 Feb 2023 at 20:53, Juri Linkov wrote:

> I tried out your patch, and everything works nicely.
> So I guess it could be pushed when you send the final version.

There you go :-)


[-- Attachment #2: 0002-New-user-option-grep-use-headings.patch --]
[-- Type: text/x-patch, Size: 6339 bytes --]

From d141b5c31718bf312cd06cd85c2865621753ad7b Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Wed, 7 Dec 2022 18:44:07 +0100
Subject: [PATCH 2/2] New user option 'grep-use-headings'

* lisp/progmodes/grep.el (grep-heading-regexp): New user option.
(grep-heading): New face.
(grep--heading-format, grep--heading-state, grep--heading-filter):
Filter function for grep processes and supporting variables.
(grep-use-headings): New user option.
(grep-mode): Use the above, if applicable.
---
 etc/NEWS                          |  9 +++++
 lisp/progmodes/grep.el            | 66 +++++++++++++++++++++++++++++++
 test/lisp/progmodes/grep-tests.el | 14 +++++++
 3 files changed, 89 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 4b0e4e6bd46..58bbd083ef8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -95,6 +95,15 @@ If you want to get back the old behavior, set the user option to the value
     (setopt gdb-locals-table-row-config
             `((type . 0) (name . 0) (value . ,gdb-locals-value-limit)))
 
+** Compile
+
+*** New user option 'grep-use-headings'.
+When non-nil, the output of Grep is split into sections, one for each
+file, instead of having file names prefixed to each line.  It is
+equivalent to the --heading option of some tools such as 'git grep'
+and 'rg'.  The headings are displayed using the new 'grep-heading'
+face.
+
 ** VC
 
 ---
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 0da16b44dda..82e9c5d8edf 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -457,6 +457,33 @@ grep-search-path
   :type '(repeat (choice (const :tag "Default" nil)
 			 (string :tag "Directory"))))
 
+(defcustom grep-use-headings nil
+  "If non-nil, subdivide grep output into sections, one per file."
+  :type 'boolean
+  :version "30.1")
+
+(defface grep-heading `((t :inherit ,grep-hit-face))
+  "Face of headings when `grep-use-headings' is non-nil."
+  :version "30.1")
+
+(defvar grep-heading-regexp
+  (rx bol
+      (or
+       (group-n 2
+         (group-n 1 (+ (not (any 0 ?\n))))
+         0)
+       (group-n 2
+        (group-n 1 (+? nonl))
+        (any ?: ?- ?=)))
+      (+ digit)
+      (any ?: ?- ?=))
+  "Regexp used to create headings from grep output lines.
+It should be anchored at beginning of line.  The first capture
+group, if present, should match the heading associated to the
+line.  The buffer range of the second capture, if present, is
+made invisible (presumably because displaying it would be
+redundant).")
+
 (defvar grep-find-abbreviate-properties
   (let ((ellipsis (if (char-displayable-p ?…) "[…]" "[...]"))
         (map (make-sparse-keymap)))
@@ -612,6 +639,40 @@ grep-filter
         (while (re-search-forward "\033\\[[0-9;]*[mK]" end 1)
           (replace-match "" t t))))))
 
+(defvar grep--heading-format
+  (eval-when-compile
+    (let ((title (propertize "%s"
+                             'font-lock-face 'grep-heading
+                             'outline-level 1)))
+      (propertize (concat title "\n") 'compilation-annotation t)))
+  "Format string of grep headings.
+This is passed to `format' with one argument, the text of the
+first capture group of `grep-heading-regexp'.")
+
+(defvar-local grep--heading-state nil
+  "Variable to keep track of the `grep--heading-filter' state.")
+
+(defun grep--heading-filter ()
+  "Filter function to add headings to output of a grep process."
+  (unless grep--heading-state
+    (setq grep--heading-state (cons (point-min-marker) nil)))
+  (save-excursion
+    (let ((limit (car grep--heading-state)))
+      ;; Move point to the old limit and update limit marker.
+      (move-marker limit (prog1 (pos-bol) (goto-char limit)))
+      (while (re-search-forward grep-heading-regexp limit t)
+        (unless (get-text-property (point) 'compilation-annotation)
+          (let ((heading (match-string-no-properties 1))
+                (start (match-beginning 2))
+                (end (match-end 2)))
+            (when start
+              (put-text-property start end 'invisible t))
+            (when (and heading (not (equal heading (cdr grep--heading-state))))
+              (save-excursion
+                (goto-char (pos-bol))
+                (insert-before-markers (format grep--heading-format heading)))
+              (setf (cdr grep--heading-state) heading))))))))
+
 (defun grep-probe (command args &optional func result)
   (let (process-file-side-effects)
     (equal (condition-case nil
@@ -906,6 +967,11 @@ grep-mode
   (add-function :filter-return (local 'kill-transform-function)
                 (lambda (string)
                   (string-replace "\0" ":" string)))
+  (when grep-use-headings
+    (add-hook 'compilation-filter-hook #'grep--heading-filter 80 t)
+    (setq-local outline-search-function #'outline-search-level
+                outline-level (lambda () (get-text-property
+                                          (point) 'outline-level))))
   (add-hook 'compilation-filter-hook #'grep-filter nil t))
 
 (defun grep--save-buffers ()
diff --git a/test/lisp/progmodes/grep-tests.el b/test/lisp/progmodes/grep-tests.el
index 39307999d6d..9b7f83086bf 100644
--- a/test/lisp/progmodes/grep-tests.el
+++ b/test/lisp/progmodes/grep-tests.el
@@ -66,4 +66,18 @@ grep-tests--rgrep-abbreviate-properties-windows-nt-sh-semantics
     (cl-letf (((symbol-function 'w32-shell-dos-semantics) #'ignore))
       (grep-tests--check-rgrep-abbreviation))))
 
+(ert-deftest grep-tests--grep-heading-regexp-without-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "filename%c123%ctext" sep sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "filename"))
+      (should (equal (match-string 2 string) (format "filename%c" sep))))))
+
+(ert-deftest grep-tests--grep-heading-regexp-with-null ()
+  (dolist (sep '(?: ?- ?=))
+    (let ((string (format "funny:0:filename%c123%ctext" 0 sep)))
+      (should (string-match grep-heading-regexp string))
+      (should (equal (match-string 1 string) "funny:0:filename"))
+      (should (equal (match-string 2 string) "funny:0:filename\0")))))
+
 ;;; grep-tests.el ends here
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Introduce-compilation-annotation-text-property.patch --]
[-- Type: text/x-patch, Size: 3953 bytes --]

From 8660f5cc050ecf3789574cfc11544b5950b8e949 Mon Sep 17 00:00:00 2001
From: Augusto Stoffel <arstoffel@gmail.com>
Date: Thu, 8 Dec 2022 21:05:10 +0100
Subject: [PATCH 1/2] Introduce 'compilation-annotation' text property

It is meant to mark parts of compilation buffers which do not
correspond to process output.

* lisp/progmodes/compile.el (compilation-insert-annotation): New
function.
(compilation-start, compilation-handle-exit): Use it.
(compilation--ensure-parse) Rely on 'compilation-annotation' property
instead of 'compilation-header-end'.
---
 lisp/progmodes/compile.el | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index ccf64fb670b..6d151db8a83 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1706,7 +1706,7 @@ compilation--ensure-parse
             (set-marker (make-marker)
                         (save-excursion
                           (goto-char (point-min))
-                          (text-property-search-forward 'compilation-header-end)
+                          (text-property-search-forward 'compilation-annotation)
                           ;; If we have no end marker, this will be
                           ;; `point-min' still.
                           (point)))))
@@ -1854,6 +1854,14 @@ compilation--update-in-progress-mode-line
   ;; buffers when it changes from nil to non-nil or vice-versa.
   (unless compilation-in-progress (force-mode-line-update t)))
 
+(defun compilation-insert-annotation (&rest args)
+  "Insert ARGS at point, adding the `compilation-annotation' text property.
+This property is used to distinguish output of the compilation
+process from additional information inserted by Emacs."
+  (let ((start (point)))
+    (apply #'insert args)
+    (put-text-property start (point) 'compilation-annotation t)))
+
 ;;;###autoload
 (defun compilation-start (command &optional mode name-function highlight-regexp
                                   continue)
@@ -1975,17 +1983,16 @@ compilation-start
             (setq-local compilation-auto-jump-to-next t))
         (when (zerop (buffer-size))
 	  ;; Output a mode setter, for saving and later reloading this buffer.
-	  (insert "-*- mode: " name-of-mode
-		  "; default-directory: "
-                  (prin1-to-string (abbreviate-file-name default-directory))
-		  " -*-\n"))
-        (insert (format "%s started at %s\n\n"
-			mode-name
-			(substring (current-time-string) 0 19))
-		command "\n")
-        ;; Mark the end of the header so that we don't interpret
-        ;; anything in it as an error.
-        (put-text-property (1- (point)) (point) 'compilation-header-end t)
+	  (compilation-insert-annotation
+           "-*- mode: " name-of-mode
+           "; default-directory: "
+           (prin1-to-string (abbreviate-file-name default-directory))
+	   " -*-\n"))
+        (compilation-insert-annotation
+         (format "%s started at %s\n\n"
+                 mode-name
+		 (substring (current-time-string) 0 19))
+	 command "\n")
 	(setq thisdir default-directory))
       (set-buffer-modified-p nil))
     ;; Pop up the compilation buffer.
@@ -2467,13 +2474,13 @@ compilation-handle-exit
 	(cur-buffer (current-buffer)))
     ;; Record where we put the message, so we can ignore it later on.
     (goto-char omax)
-    (insert ?\n mode-name " " (car status))
+    (compilation-insert-annotation ?\n mode-name " " (car status))
     (if (and (numberp compilation-window-height)
 	     (zerop compilation-window-height))
 	(message "%s" (cdr status)))
     (if (bolp)
 	(forward-char -1))
-    (insert " at " (substring (current-time-string) 0 19))
+    (compilation-insert-annotation " at " (substring (current-time-string) 0 19))
     (goto-char (point-max))
     ;; Prevent that message from being recognized as a compilation error.
     (add-text-properties omax (point)
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-27 19:06                               ` Augusto Stoffel
@ 2023-02-27 19:15                                 ` Juri Linkov
  2023-02-28 17:24                                 ` Juri Linkov
  1 sibling, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2023-02-27 19:15 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: Robert Pluim, Eli Zaretskii, 59888, stefankangas

close 59888 30.0.50
thanks

>> I tried out your patch, and everything works nicely.
>> So I guess it could be pushed when you send the final version.
>
> There you go :-)

Thanks for this useful feature.  Now pushed to master.
(And immediately customized it to t ;-)





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-27 19:06                               ` Augusto Stoffel
  2023-02-27 19:15                                 ` Juri Linkov
@ 2023-02-28 17:24                                 ` Juri Linkov
  2023-02-28 18:17                                   ` Augusto Stoffel
  1 sibling, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2023-02-28 17:24 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

> +(defvar grep-heading-regexp
> +  (rx bol
> +      (or
> +       (group-n 2
> +         (group-n 1 (+ (not (any 0 ?\n))))
> +         0)
> +       (group-n 2
> +        (group-n 1 (+? nonl))
> +        (any ?: ?- ?=)))
> +      (+ digit)
> +      (any ?: ?- ?=))

I wonder what is the reason for this regexp to be different
from grep-regexp-alist?  Especially with such additional characters
as ?- and ?=.  This mismatch causes wrong handling of files when
file names contain these characters.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-28 17:24                                 ` Juri Linkov
@ 2023-02-28 18:17                                   ` Augusto Stoffel
  2023-03-01 17:52                                     ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Augusto Stoffel @ 2023-02-28 18:17 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 59888

On Tue, 28 Feb 2023 at 19:24, Juri Linkov wrote:

>> +(defvar grep-heading-regexp
>> +  (rx bol
>> +      (or
>> +       (group-n 2
>> +         (group-n 1 (+ (not (any 0 ?\n))))
>> +         0)
>> +       (group-n 2
>> +        (group-n 1 (+? nonl))
>> +        (any ?: ?- ?=)))
>> +      (+ digit)
>> +      (any ?: ?- ?=))
>
> I wonder what is the reason for this regexp to be different
> from grep-regexp-alist?  Especially with such additional characters
> as ?- and ?=.  This mismatch causes wrong handling of files when
> file names contain these characters.

This is because of context lines:

--8<---------------cut here---------------start------------->8---
$ git grep -nC 1 grep-use-headings
etc/NEWS-99-
etc/NEWS:100:*** New user option 'grep-use-headings'.
etc/NEWS-101-When non-nil, the output of Grep is split into sections, one for each
--
lisp/progmodes/grep.el-459-
lisp/progmodes/grep.el:460:(defcustom grep-use-headings nil
lisp/progmodes/grep.el-461-  "If non-nil, subdivide grep output into sections, one per file."
--
lisp/progmodes/grep.el-465-(defface grep-heading `((t :inherit ,grep-hit-face))
lisp/progmodes/grep.el:466:  "Face of headings when `grep-use-headings' is non-nil."
lisp/progmodes/grep.el-467-  :version "30.1")
--
lisp/progmodes/grep.el-969-                  (string-replace "\0" ":" string)))
lisp/progmodes/grep.el:970:  (when grep-use-headings
lisp/progmodes/grep.el-971-    (add-hook 'compilation-filter-hook #'grep--heading-filter 80 t)
--8<---------------cut here---------------end--------------->8---

(I forget which program uses the =LINE= syntax)

At least when using grep --null, I think there is no confusion possible.  I
wrote a unit test that purports to prove that.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#59888: [PATCH] Add 'grep-use-headings'
  2023-02-28 18:17                                   ` Augusto Stoffel
@ 2023-03-01 17:52                                     ` Juri Linkov
  0 siblings, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2023-03-01 17:52 UTC (permalink / raw)
  To: Augusto Stoffel; +Cc: 59888

>>> +      (any ?: ?- ?=))
>>
>> I wonder what is the reason for this regexp to be different
>> from grep-regexp-alist?  Especially with such additional characters
>> as ?- and ?=.  This mismatch causes wrong handling of files when
>> file names contain these characters.
>
> This is because of context lines:
>
> $ git grep -nC 1 grep-use-headings
> lisp/progmodes/grep.el-459-
> lisp/progmodes/grep.el:460:(defcustom grep-use-headings nil
> lisp/progmodes/grep.el-461-  "If non-nil, subdivide grep output into sections, one per file."
> ...
> At least when using grep --null, I think there is no confusion possible.  I
> wrote a unit test that purports to prove that.

Thanks for mentioning --null, I completely forgot about it.
I've customized 'grep-find-template' to "rg --no-heading"
because ripgrep is fast, but since its headings are not
supported by grep.el, so also needed "--no-heading".
And now after adding "--null" to "rg --no-heading --null"
'grep-use-headings' correctly handles context lines
and file names with numbers separated by dashes.





^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2023-03-01 17:52 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-07 17:57 bug#59888: [PATCH] Add 'grep-heading-mode' Augusto Stoffel
2022-12-07 18:14 ` Eli Zaretskii
2022-12-08  8:59   ` Augusto Stoffel
2022-12-08 10:57     ` Eli Zaretskii
2022-12-08  0:19 ` Stefan Kangas
2022-12-08  9:06   ` Augusto Stoffel
2022-12-09  7:23     ` Juri Linkov
2022-12-09 11:58       ` Augusto Stoffel
2022-12-09 12:18       ` bug#59888: [PATCH] Add 'grep-use-headings' Augusto Stoffel
2022-12-09 19:36         ` Eli Zaretskii
2022-12-09 20:03           ` Augusto Stoffel
2022-12-09 20:29             ` Eli Zaretskii
2022-12-10 20:08               ` Augusto Stoffel
2022-12-10 20:16                 ` Eli Zaretskii
2022-12-11 11:30                   ` Augusto Stoffel
2022-12-15  8:05                     ` Juri Linkov
2023-02-25  8:34                       ` Augusto Stoffel
2023-02-25 18:00                         ` Juri Linkov
2023-02-26 13:17                         ` Robert Pluim
2023-02-26 15:07                           ` Augusto Stoffel
2023-02-27  6:24                             ` Robert Pluim
2023-02-27 11:26                               ` Augusto Stoffel
2023-02-27 16:51                                 ` Robert Pluim
2023-02-27 18:53                             ` Juri Linkov
2023-02-27 19:06                               ` Augusto Stoffel
2023-02-27 19:15                                 ` Juri Linkov
2023-02-28 17:24                                 ` Juri Linkov
2023-02-28 18:17                                   ` Augusto Stoffel
2023-03-01 17:52                                     ` Juri Linkov
2022-12-09 20:40             ` Gregory Heytings
2022-12-10 17:24             ` Juri Linkov
2022-12-08  9:57 ` bug#59888: [PATCH] Add 'grep-heading-mode' Mattias Engdegård
2022-12-08 10:28   ` Augusto Stoffel
2022-12-08 10:48     ` Mattias Engdegård
2023-02-27 14:18       ` Mattias Engdegård
2022-12-09  7:28 ` Juri Linkov
2022-12-09 11:58   ` Augusto Stoffel

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.