unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Visuwesh <visuweshm@gmail.com>
To: Jim Porter <jporterbugs@gmail.com>
Cc: 70820@debbugs.gnu.org
Subject: bug#70820: [PATCH] Editable grep buffers
Date: Wed, 08 May 2024 10:41:10 +0530	[thread overview]
Message-ID: <87cypwlwgh.fsf@gmail.com> (raw)
In-Reply-To: <a7395437-0f93-f7fc-da14-41b7ca65d291@gmail.com> (Jim Porter's message of "Tue, 7 May 2024 21:11:42 -0700")

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

[செவ்வாய் மே 07, 2024] Jim Porter wrote:

> On 5/7/2024 8:12 PM, Visuwesh wrote:
>> Thanks for your input.  If I missed something from wgrep that you use,
>> please let me known.  I will play around with wgrep in some time to
>> learn more about what it offers myself.
>
> In addition to the things you mentioned, here are the most important
> features from wgrep for me:

Thanks.

> * Mark all non-result parts of the buffer (the command string, file
>   names, line numbers, etc) as read-only. This is especially valuable
>   if you want to use 'query-replace' or similar to modify the
>   results. Then you can't inadvertently edit those bits.

This is now done.

> * Fontify any results with changes (both in the grep-mode buffer and
>   the original files). This is really useful for being able to see
>   what I've changed.

I agree that it would be nice to have this in *grep* buffer but I would
like to avoid editing the file on-the-fly since it introduces typing lag
IME with occur-edit-mode.  If you want to know the edits that were made,
you can use diff-buffer-with-file so I hope leaving out the highlighting
in the file would be okay.

> * Adding all the necessary hooks/functions so other grep-like modes
>   can use this. For example, see this file from wgrep, which lets you
>   use wgrep with ag.el:
>   <https://github.com/mhayashi1120/Emacs-wgrep/blob/master/wgrep-ag.el>. (This
>   matters to me partly because I'm the author of Urgrep - a "universal
>   recursive grep" mode that can use any grep-like program to do
>   searches. I've added my own support in Urgrep for wgrep.)

With grep-edit-minor-mode, as long as the compilation-message
text-property is present at the beginning of the line, you do not need
to do anything extra.  I look at this to gain the information about the
filename and the line number.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: grep-edit.diff --]
[-- Type: text/x-diff, Size: 4328 bytes --]

diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 657349cbdff..517d1bd5ecd 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -31,6 +31,7 @@
 
 (eval-when-compile (require 'cl-lib))
 (require 'compile)
+(require 'track-changes)
 
 (defgroup grep nil
   "Run `grep' and display the results."
@@ -295,6 +296,8 @@ grep-mode-map
     (define-key map "}" #'compilation-next-file)
     (define-key map "\t" #'compilation-next-error)
     (define-key map [backtab] #'compilation-previous-error)
+
+    (define-key map "e" #'grep-edit-minor-mode)
     map)
   "Keymap for grep buffers.
 `compilation-minor-mode-map' is a cdr of this.")
@@ -1029,6 +1032,86 @@ grep
 		       command-args)
 		     #'grep-mode))
 
+(defvar-local grep-edit--tracker nil
+  "ID of the `track-changes' tracker.")
+
+(defun grep-edit--track-changes-signal (_id &optional _distance)
+  ;; Empty because we want to simply accumulate the changes at end
+  ;; when the user calls the finish function.
+  nil)
+
+(defun grep-edit--track-changes-finalise (beg end _before)
+  (let ((grep-buf (current-buffer))
+        (cur-res beg))                  ; Point at current grep result.
+    (save-excursion
+      (while (<= cur-res end)
+        (goto-char cur-res)
+        (let* ((change-beg (next-single-char-property-change (pos-bol) 'compilation-message))
+               ;; `1-' is required to ignore the newline.
+               (change-end (1- (next-single-char-property-change (pos-eol) 'compilation-message)))
+               (loc (compilation--message->loc
+                     (get-text-property (pos-bol) 'compilation-message)))
+               (line (compilation--loc->line loc))
+               (file (caar (compilation--loc->file-struct loc))))
+          (with-current-buffer (find-file-noselect file)
+            (save-excursion
+              (goto-char (point-min))
+              (forward-line (1- line))
+              (delete-region (pos-bol) (pos-eol))
+              (insert-buffer-substring-no-properties grep-buf change-beg change-end))))
+        (setq cur-res  (next-single-property-change cur-res 'compilation-message))))))
+
+(defun grep-edit--mark-read-only ()
+  "Mark annotations and info regions read-only."
+  (save-excursion
+    (goto-char (point-min))
+    (let ((inhibit-read-only t)
+          match)
+      (while (setq match (text-property-search-forward 'compilation-annotation))
+        (add-text-properties (prop-match-beginning match) (prop-match-end match)
+                             '(read-only t)))
+      (goto-char (point-min))
+      (while (setq match (text-property-search-forward 'compilation-message))
+        (add-text-properties (prop-match-beginning match) (prop-match-end match)
+                             '(read-only t))))))
+
+(define-minor-mode grep-edit-minor-mode
+  "Minor mode for editing *grep* buffers.
+In this mode, changes to the *grep* buffer are applied to the
+originating files upon saving using \\[grep-save-changes]."
+  :lighter " Grep-Edit"
+  (if (null grep-edit-minor-mode)
+      (progn
+        (setq buffer-read-only t)
+        (buffer-disable-undo)
+        (use-local-map grep-mode-map))
+    (grep-edit--mark-read-only)
+    (unless grep-edit--tracker
+      (use-local-map grep-edit-minor-mode-map)
+      (setq buffer-read-only nil)
+      (buffer-enable-undo)
+      (setq grep-edit--tracker
+            (track-changes-register #'grep-edit--track-changes-signal
+                                    :disjoint t)))
+    (message (substitute-command-keys
+              "Editing: \\[grep-edit-save-changes] to return to Grep mode."))))
+
+(defun grep-edit-save-changes ()
+  "Save the changes made to the *grep* buffer."
+  (interactive)
+  (when (and grep-edit-minor-mode grep-edit--tracker)
+    (track-changes-fetch grep-edit--tracker #'grep-edit--track-changes-finalise)
+    (message "Applied edits, switching to Grep mode.")
+    (track-changes-unregister grep-edit--tracker)
+    (setq grep-edit--tracker nil)
+    (grep-edit-minor-mode -1)))
+
+(defvar grep-edit-minor-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map text-mode-map)
+    (define-key map (kbd "C-c C-c") #'grep-edit-save-changes)
+    map)
+  "Keymap for `grep-edit-minor-mode'.")
 
 ;;;###autoload
 (defun grep-find (command-args)

  reply	other threads:[~2024-05-08  5:11 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-07 16:25 bug#70820: [PATCH] Editable grep buffers Visuwesh
2024-05-07 17:23 ` Jim Porter
2024-05-08  3:12   ` Visuwesh
2024-05-08  4:11     ` Jim Porter
2024-05-08  5:11       ` Visuwesh [this message]
2024-05-18 13:23   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-07 18:08 ` Eli Zaretskii
2024-05-08  3:22   ` Visuwesh
2024-05-08 11:58     ` Eli Zaretskii
2024-05-08 12:18       ` Visuwesh
2024-05-08 13:49         ` Eli Zaretskii
2024-05-09 10:32           ` Visuwesh
2024-05-12  4:45             ` Visuwesh
2024-05-18  9:28               ` Eli Zaretskii
2024-05-18 13:35                 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-18 15:44                   ` Eli Zaretskii
2024-05-18 16:27                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-18 16:28                       ` Eli Zaretskii
2024-05-20 10:10                         ` Visuwesh
2024-05-18 13:34           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-08 17:37       ` Jim Porter
2024-05-08 18:42         ` Eli Zaretskii
2024-05-08 19:19           ` Jim Porter
2024-05-08 19:23             ` Jim Porter
2024-05-09  4:41               ` Eli Zaretskii
2024-05-09 16:14                 ` Jim Porter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87cypwlwgh.fsf@gmail.com \
    --to=visuweshm@gmail.com \
    --cc=70820@debbugs.gnu.org \
    --cc=jporterbugs@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).