From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Visuwesh Newsgroups: gmane.emacs.bugs Subject: bug#70820: [PATCH] Editable grep buffers Date: Tue, 07 May 2024 21:55:09 +0530 Message-ID: <87seytlhcq.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="26882"; mail-complaints-to="usenet@ciao.gmane.io" To: 70820@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue May 07 18:26:01 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1s4Ndh-0006i4-4i for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 07 May 2024 18:26:01 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s4NdO-0005Kh-5B; Tue, 07 May 2024 12:25:42 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s4NdJ-0005CU-9C for bug-gnu-emacs@gnu.org; Tue, 07 May 2024 12:25:37 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1s4NdJ-0003UQ-1L for bug-gnu-emacs@gnu.org; Tue, 07 May 2024 12:25:37 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1s4Ndh-0003Wg-TM for bug-gnu-emacs@gnu.org; Tue, 07 May 2024 12:26:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Visuwesh Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 07 May 2024 16:26:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 70820 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.171509915013541 (code B ref -1); Tue, 07 May 2024 16:26:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 7 May 2024 16:25:50 +0000 Original-Received: from localhost ([127.0.0.1]:43511 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1s4NdW-0003WL-2X for submit@debbugs.gnu.org; Tue, 07 May 2024 12:25:50 -0400 Original-Received: from lists.gnu.org ([2001:470:142::17]:57954) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1s4NdT-0003WF-5b for submit@debbugs.gnu.org; Tue, 07 May 2024 12:25:48 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s4Ncy-00052q-Ce for bug-gnu-emacs@gnu.org; Tue, 07 May 2024 12:25:16 -0400 Original-Received: from mail-oo1-xc43.google.com ([2607:f8b0:4864:20::c43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1s4Ncw-0002as-JA for bug-gnu-emacs@gnu.org; Tue, 07 May 2024 12:25:16 -0400 Original-Received: by mail-oo1-xc43.google.com with SMTP id 006d021491bc7-5ac90ad396dso1968566eaf.3 for ; Tue, 07 May 2024 09:25:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1715099113; x=1715703913; darn=gnu.org; h=mime-version:message-id:date:subject:to:from:from:to:cc:subject :date:message-id:reply-to; bh=QFvwqEI7oz5LCbyvhuHly8RuI6z9DKFX2FBUZ+LFkGc=; b=VC3SZj46CKO1V90QGyWz5k1HtONFOJUbqz6032MaG/JdtJVESK4kazU7ykHAgvmhJs ajkSc3Qbd62HQ6wXhfMF0dscXQdp4KjRUVQa41A/K7PQS+6YdVIlmFGqh1lJBRUL+bu0 SosXUG0VcLck+FxTKZ36aaZge76SkyCcBE1R2DqfqzMhBJQgvNL/eVmpdhQbMSSbnWAP CgEI5NU0w6s9fONbPDPoFmTHvLZzFDP2W8wgh7ljDxyT6PqELI3xumrFWOrUQkI1jfoP V+7WVTobZ5aLVprfSJOXX5BK9lBrzquonY14TBAGw19hpQsWR6nrnC9IvxlQH7xOsuBr 4pUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1715099113; x=1715703913; h=mime-version:message-id:date:subject:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=QFvwqEI7oz5LCbyvhuHly8RuI6z9DKFX2FBUZ+LFkGc=; b=dopwIJxDiP3Do5hlQxj/5W0/rOfNI1a3V9fzI1UGf1lZqVZbyPjk9EQBfF4d4Vq8tU TbChdLihq2WSzJsMIVz/Hw4JbN0Hd9at1HCTCMOTbKP1EAFWZqMnqFIFA8RdQhOPYvSY syVsFL4Du9rZr2tFvLkJDtZPDgwjpX5QrB3ac7sNHkFbk6hBxIIw1J80CamnxKfYI9rf Qbva57qFPhVPVwzR33vNFJBx+yHHEEfkc3pFA/7//ZyDoRI6FzIiFn3Wv8tnqza1Bsva wHVHGm1Gw771d5muk+f7PIWgqJvCDAIvAJR0xAIp0SxGFMZzvphk7mwR9I2WxxBqgwZX Mmhw== X-Gm-Message-State: AOJu0YzlLqIkccqkeZzFx6r5ZuumwH9JomkI6PF16tIpebG5lBHOwZND m2IK07VMH/3V3hQFwz7Wc8fOAyulVnJXr+k+3t1GIwDvqNZLssSPtKxiuMRI X-Google-Smtp-Source: AGHT+IHBgHVn8UtWUV9d5xZRB9OHZl8bs9y7S+7YP9VP5HxJM7KrNRu4kB+nD7jzg+uqQwiX8b060g== X-Received: by 2002:a05:6358:e488:b0:192:2540:554c with SMTP id e5c5f4694b2df-192d2a1776amr29101655d.1.1715099112631; Tue, 07 May 2024 09:25:12 -0700 (PDT) Original-Received: from localhost ([49.204.134.76]) by smtp.gmail.com with ESMTPSA id k133-20020a636f8b000000b0062d54efed87sm1207817pgc.53.2024.05.07.09.25.11 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 May 2024 09:25:11 -0700 (PDT) Received-SPF: pass client-ip=2607:f8b0:4864:20::c43; envelope-from=visuweshm@gmail.com; helo=mail-oo1-xc43.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:284645 Archived-At: --=-=-= Content-Type: text/plain 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' --=-=-= Content-Type: text/patch Content-Disposition: attachment; filename=grep-edit.diff 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) --=-=-=--