From: Visuwesh <visuweshm@gmail.com>
To: 70820@debbugs.gnu.org
Subject: bug#70820: [PATCH] Editable grep buffers
Date: Tue, 07 May 2024 21:55:09 +0530 [thread overview]
Message-ID: <87seytlhcq.fsf@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1779 bytes --]
Tags: patch
Attached patch is a proof of concept for an occur-edit-mode alike for
*grep* buffers. It uses the new track-changes library to track the
edits made in the *grep* buffer to then finally save these edits to the
corresponding files. I've tested this with:
1. pure deletions: If you have a match that says "(cur-beg start"
and you change it to "(cur- start". This is special because
track-changes-fetch passes equal BEG and END to
grep-edit--track-changes-finalise.
2. edits: something like "(cur-beg start" -> "(cur-beg start balh"
is handled like you would expect.
3. edits with newline: if the edit includes a newline, then that is
reproduced.
and what is not handled currently: deleting a match line to imply
deletion of that line from the matched file. I don't know how to handle
this currently, I need to learn the library more.
There's also definitely a million more cases that I didn't anticipate
when I wrote the logic for grep-edit--track-changes-finalise.
I'm sending the patch now to see if there's enough interest before I go
about fixing the edge cases (there's bug#52815). If there is enough
interest, I will take a shot at implementing something like this for
xref result buffers too.
In GNU Emacs 30.0.50 (build 8, x86_64-pc-linux-gnu, X toolkit, cairo
version 1.18.0, Xaw scroll bars) of 2024-05-07 built on astatine
Repository revision: 4b31074f5f49898ba0499a2b617cad425750eafa
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101011
System Description: Debian GNU/Linux trixie/sid
Configured using:
'configure --with-sound=alsa --with-x-toolkit=lucid --with-json
--without-xaw3d --without-gconf --without-libsystemd --with-cairo
--with-xft'
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: grep-edit.diff --]
[-- Type: text/patch, Size: 3654 bytes --]
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 657349cbdff..3fa6fce0e8d 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,71 @@ 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))))))
+
+(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))
+ (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)
next reply other threads:[~2024-05-07 16:25 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-07 16:25 Visuwesh [this message]
2024-05-07 17:23 ` bug#70820: [PATCH] Editable grep buffers Jim Porter
2024-05-08 3:12 ` Visuwesh
2024-05-08 4:11 ` Jim Porter
2024-05-08 5:11 ` Visuwesh
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-07-28 8:33 ` Visuwesh
2024-08-14 0:30 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-14 2:43 ` Visuwesh
2024-08-14 11:37 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-08-31 7:54 ` Eli Zaretskii
2024-08-31 8:03 ` Visuwesh
2024-09-09 14:39 ` Visuwesh
2024-09-14 9:43 ` Eli Zaretskii
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=87seytlhcq.fsf@gmail.com \
--to=visuweshm@gmail.com \
--cc=70820@debbugs.gnu.org \
/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).