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: Sun, 28 Jul 2024 14:03:32 +0530 Message-ID: <87le1lj4pv.fsf@gmail.com> References: <87seytlhcq.fsf@gmail.com> <86pltxa40q.fsf@gnu.org> <87jzk5kmwk.fsf@gmail.com> <86ikzoa51h.fsf@gnu.org> <878r0klcp1.fsf@gmail.com> <864jb89zwq.fsf@gnu.org> <87wmo3jmws.fsf@gmail.com> <87fruny6xe.fsf@gmail.com> <86le47eafb.fsf@gnu.org> <86pltjceft.fsf@gnu.org> <86ikzbcces.fsf@gnu.org> 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="21837"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: 70820@debbugs.gnu.org, Stefan Monnier To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Jul 28 10:36:10 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 1sXzNx-0005X6-VK for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 28 Jul 2024 10:36:10 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sXzNj-00062R-89; Sun, 28 Jul 2024 04:35:55 -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 1sXzNg-00062G-ON for bug-gnu-emacs@gnu.org; Sun, 28 Jul 2024 04:35:53 -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 1sXzNf-0008I0-0a for bug-gnu-emacs@gnu.org; Sun, 28 Jul 2024 04:35:51 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:References:Date:In-Reply-To:From:To:Subject; bh=1tOAnwwLjPVgrVE/9csFJMnLdS1wI0Fu/Tmne9LP8KM=; b=WoDHSu6b/0gRVKpnL76IVgZbsDoZBwaOcUmOPck96Zxj9dyqCFnu801eKZgrqAZgUL8J1X9xV0fDHZUA4Qg6iuQzRB13svsR+SaR/RZyNbH8t8+CIRn6483xU1ySxHXkrj+zAK/hVOF+3a2pUvktZLOuNLIF1np1NGIPWoypqppbA7Lykplht02IecUgou9yHyigAEVA+DEqOtkojZRrKlVDWcIDkJALYqPgECn5xqmIiX8Aabk/zOPLNSyk+KTdeLuw0Si4oDl1mIlIHj76BUs2z/Tfh+d9V6gcuETbynQtaHoVEkEBs4ZnU8ojfSb0A+Pc8cUlDvkgkUCYsAZnMw==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1sXzNp-0001QQ-RK for bug-gnu-emacs@gnu.org; Sun, 28 Jul 2024 04:36:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Visuwesh Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 28 Jul 2024 08:36:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 70820 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 70820-submit@debbugs.gnu.org id=B70820.17221557055407 (code B ref 70820); Sun, 28 Jul 2024 08:36:01 +0000 Original-Received: (at 70820) by debbugs.gnu.org; 28 Jul 2024 08:35:05 +0000 Original-Received: from localhost ([127.0.0.1]:42685 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sXzMu-0001P8-C9 for submit@debbugs.gnu.org; Sun, 28 Jul 2024 04:35:05 -0400 Original-Received: from mail-oi1-f196.google.com ([209.85.167.196]:52501) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sXzMs-0001OX-5L for 70820@debbugs.gnu.org; Sun, 28 Jul 2024 04:35:03 -0400 Original-Received: by mail-oi1-f196.google.com with SMTP id 5614622812f47-3db18102406so1779207b6e.1 for <70820@debbugs.gnu.org>; Sun, 28 Jul 2024 01:34:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1722155625; x=1722760425; darn=debbugs.gnu.org; h=mime-version:user-agent:references:message-id:date:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=1tOAnwwLjPVgrVE/9csFJMnLdS1wI0Fu/Tmne9LP8KM=; b=HuLkTwEP+r3naBXb7/+mdp4VbGti47F2K2LUVP0WTSIN5IiDhC6jYsK6Uia6SqI63o g0E1dykF+3gFKpju9wkLms31HGJAz48icldRGfMFoACIc7D4mtfsKsHqRenY1p27myaC 3gKbhqH7xweikjLQOz5qvg5ViQbvcnHiX4O+zfzW86kILMTvEfqGTmxqei/hYttGc+98 qq6Ls0p3knk93RF982NnpmvDv670i6NUkdc0l1VYHML7FR4fHhWvA3yn6340Jp8Y5mpo owKXp/47faf9qkf40m2Mh4sNRu0Xvl0ou1aSZBxv1LSqkrRwB23BQAOgk3dXYKtY1aun V7ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722155625; x=1722760425; h=mime-version:user-agent:references:message-id:date:in-reply-to :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=1tOAnwwLjPVgrVE/9csFJMnLdS1wI0Fu/Tmne9LP8KM=; b=FUbN44rkDmrmGro42obdT46Lh9XoMnYuZ34EVcfK/GvkRZu+z+Jqk1nqC95dbhj1zR KExf30rtIwr5NNEazZSI/dTiofP4HoMjGc+IIzKcANAW4FCnoYgaWu6CuRD6VZuviajD ZvPl/YWFz1+jAluDw2jpodRi80YFNZiDvwOVJs1USW+XhATSQDUP3XqTCnh4qrlZebEV tVJ6b5QrPqIelrzVJOWi5gVxhyLRrlcXxPV1IRLf1XqiUTD9alTo1VvTSLBt4H3nBIoa wti1/toNilC5X1l2qmAm1a5zl4PWSp/iibLrjDL98TY/4JuMuMcns0xZn3DtVJu9tb4p HQPw== X-Forwarded-Encrypted: i=1; AJvYcCWBFqhmUTSgBk9abaG5Xp77ou+MfpsnEKJmmIdD72D8pYKikubfS9DEs7Tgil7dd5KCN/NX96ehdk8LB2Z3X2NEwi9HViU= X-Gm-Message-State: AOJu0YzLQFHdKHTdHedtzRX7ohmVigYcJPDnPX3gJn0bgBKTMrSQ4UvT Rcf4tTXAvd2zLxggVdcAQ08PxrFriWrwogbeLvCcrZgZQl0PPOqH X-Google-Smtp-Source: AGHT+IFouJD4O3A/8HJ2eNLO3LW3w5A7drT9FOyMtne6QqJGcZyS99ekNCpdDm8MVks89hMRjon/BQ== X-Received: by 2002:a05:6808:11c1:b0:3db:269b:964b with SMTP id 5614622812f47-3db269b984dmr5554503b6e.12.1722155625242; Sun, 28 Jul 2024 01:33:45 -0700 (PDT) Original-Received: from localhost ([49.204.119.35]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-70ead86ff31sm5253104b3a.144.2024.07.28.01.33.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 28 Jul 2024 01:33:44 -0700 (PDT) In-Reply-To: <86ikzbcces.fsf@gnu.org> (Eli Zaretskii's message of "Sat, 18 May 2024 19:28:27 +0300") 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:289460 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable [=E0=AE=9A=E0=AE=A9=E0=AE=BF =E0=AE=AE=E0=AF=87 18, 2024] Eli Zaretskii wro= te: >> From: Stefan Monnier >> Cc: visuweshm@gmail.com, 70820@debbugs.gnu.org >> Date: Sat, 18 May 2024 12:27:06 -0400 >>=20 >> >> These are properties which the major mode (unconditionally) added, so= it >> >> doesn't seem unfriendly to remove them unconditionally when switching= to >> >> an unrelated major mode. >> > Yes, but how does compilation-mode know the other major-mode is >> > "unrelated"? It could be very related, as this discussion >> > demonstrates. >>=20 >> If it's related it has access to internals, so it can so things like >> disabling `compilation--remoave-properties`. > > OK, so my suggestion to Visuwesh is the best way of dealing with this. > Fine by me. Sorry for the long delay. I finally got the time to work on this properly. The attached patch uses a major-mode, akin to wdired-mode like Stefan suggested in another message. This side-steps previous issues with buffer-local variables and compilation--remove-properties. If this approach is okay, I will work on updating the documentation, etc. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=grep-edit-v2.diff diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index b18eb81fee1..867ebc92d75 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -2829,6 +2829,53 @@ compilation-find-buffer (current-buffer) (next-error-find-buffer avoid-current 'compilation-buffer-internal-p))) +(defun compilation--update-markers (loc marker screen-columns first-column) + "Update markers in LOC, and set MARKER to location pointed by LOC. +SCREEN-COLUMNS and FIRST-COLUMN are the value of +`compilation-error-screen-columns' and `compilation-first-column' to use +if they are not set buffer-locally in the target buffer." + (with-current-buffer + (if (bufferp (caar (compilation--loc->file-struct loc))) + (caar (compilation--loc->file-struct loc)) + (apply #'compilation-find-file + marker + (caar (compilation--loc->file-struct loc)) + (cadr (car (compilation--loc->file-struct loc))) + (compilation--file-struct->formats + (compilation--loc->file-struct loc)))) + (let ((screen-columns + ;; Obey the compilation-error-screen-columns of the target + ;; buffer if its major mode set it buffer-locally. + (if (local-variable-p 'compilation-error-screen-columns) + compilation-error-screen-columns screen-columns)) + (compilation-first-column + (if (local-variable-p 'compilation-first-column) + compilation-first-column first-column)) + (last 1)) + (save-restriction + (widen) + (goto-char (point-min)) + ;; Treat file's found lines in forward order, 1 by 1. + (dolist (line (reverse (cddr (compilation--loc->file-struct loc)))) + (when (car line) ; else this is a filename without a line# + (compilation-beginning-of-line (- (car line) last -1)) + (setq last (car line))) + ;; Treat line's found columns and store/update a marker for each. + (dolist (col (cdr line)) + (if (compilation--loc->col col) + (if (eq (compilation--loc->col col) -1) + ;; Special case for range end. + (end-of-line) + (compilation-move-to-column (compilation--loc->col col) + screen-columns)) + (beginning-of-line) + (skip-chars-forward " \t")) + (if (compilation--loc->marker col) + (set-marker (compilation--loc->marker col) (point)) + (setf (compilation--loc->marker col) (point-marker))) + ;; (setf (compilation--loc->timestamp col) timestamp) + )))))) + ;;;###autoload (defun compilation-next-error-function (n &optional reset) "Advance to the next error message and visit the file where the error was. @@ -2838,7 +2885,6 @@ compilation-next-error-function (setq compilation-current-error nil)) (let* ((screen-columns compilation-error-screen-columns) (first-column compilation-first-column) - (last 1) (msg (compilation-next-error (or n 1) nil (or compilation-current-error compilation-messages-start @@ -2850,9 +2896,9 @@ compilation-next-error-function (user-error "No next error")) (setq compilation-current-error (point-marker) overlay-arrow-position - (if (bolp) - compilation-current-error - (copy-marker (line-beginning-position)))) + (if (bolp) + compilation-current-error + (copy-marker (line-beginning-position)))) ;; If loc contains no marker, no error in that file has been visited. ;; If the marker is invalid the buffer has been killed. ;; So, recalculate all markers for that file. @@ -2869,46 +2915,7 @@ compilation-next-error-function ;; (equal (compilation--loc->timestamp loc) ;; (setq timestamp compilation-buffer-modtime))) ) - (with-current-buffer - (if (bufferp (caar (compilation--loc->file-struct loc))) - (caar (compilation--loc->file-struct loc)) - (apply #'compilation-find-file - marker - (caar (compilation--loc->file-struct loc)) - (cadr (car (compilation--loc->file-struct loc))) - (compilation--file-struct->formats - (compilation--loc->file-struct loc)))) - (let ((screen-columns - ;; Obey the compilation-error-screen-columns of the target - ;; buffer if its major mode set it buffer-locally. - (if (local-variable-p 'compilation-error-screen-columns) - compilation-error-screen-columns screen-columns)) - (compilation-first-column - (if (local-variable-p 'compilation-first-column) - compilation-first-column first-column))) - (save-restriction - (widen) - (goto-char (point-min)) - ;; Treat file's found lines in forward order, 1 by 1. - (dolist (line (reverse (cddr (compilation--loc->file-struct loc)))) - (when (car line) ; else this is a filename without a line# - (compilation-beginning-of-line (- (car line) last -1)) - (setq last (car line))) - ;; Treat line's found columns and store/update a marker for each. - (dolist (col (cdr line)) - (if (compilation--loc->col col) - (if (eq (compilation--loc->col col) -1) - ;; Special case for range end. - (end-of-line) - (compilation-move-to-column (compilation--loc->col col) - screen-columns)) - (beginning-of-line) - (skip-chars-forward " \t")) - (if (compilation--loc->marker col) - (set-marker (compilation--loc->marker col) (point)) - (setf (compilation--loc->marker col) (point-marker))) - ;; (setf (compilation--loc->timestamp col) timestamp) - )))))) + (compilation--update-markers loc marker screen-columns first-column)) (compilation-goto-locus marker (compilation--loc->marker loc) (compilation--loc->marker end-loc)) (setf (compilation--loc->visited loc) t))) diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el index 657349cbdff..605e763b444 100644 --- a/lisp/progmodes/grep.el +++ b/lisp/progmodes/grep.el @@ -295,6 +295,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-change-to-grep-edit-mode) map) "Keymap for grep buffers. `compilation-minor-mode-map' is a cdr of this.") @@ -1029,6 +1031,90 @@ grep command-args) #'grep-mode)) +(defun grep-edit--prepare-buffer () + "Mark relevant regions read-only, and add relevant occur text-properties." + (save-excursion + (goto-char (point-min)) + (let ((inhibit-read-only t) + (dummy (make-marker)) + 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 occur-prefix t)) + (let ((loc (compilation--message->loc (prop-match-value match))) + m) + ;; Update the markers if necessary. + (unless (and (compilation--loc->marker loc) + (marker-buffer (compilation--loc->marker loc))) + (compilation--update-markers loc dummy compilation-error-screen-columns compilation-first-column)) + (setq m (compilation--loc->marker loc)) + (add-text-properties (prop-match-beginning match) + (or (next-single-property-change + (prop-match-end match) + 'compilation-message) + (1+ (pos-eol))) + `(occur-target ((,m . ,m))))))))) + +(defvar grep-edit-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-mode'.") + +(defvar grep-edit-mode-hook nil + "Hooks run when changing to Grep-Edit mode.") + +(defun grep-edit-mode () + "Major mode for editing *grep* buffers. +In this mode, changes to the *grep* buffer are applied to the +originating files. +\\ +Type \\[grep-edit-save-changes] to exit Grep-Edit mode, return to Grep +mode. + +The only editable texts in a Grep-Edit buffer are the match results." + (interactive) + (error "This mode can be enabled only by `grep-change-to-grep-edit-mode'")) +(put 'grep-edit-mode 'mode-class 'special) + +(defun grep-change-to-grep-edit-mode () + "Switch to `grep-edit-mode' to edit *grep* buffer." + (interactive) + (unless (derived-mode-p 'grep-mode) + (error "Not a Grep buffer")) + (when (get-buffer-process (current-buffer)) + (error "Cannot switch when grep is running")) + (use-local-map grep-edit-mode-map) + (grep-edit--prepare-buffer) + (setq buffer-read-only nil) + (setq major-mode 'grep-edit-mode) + (setq mode-name "Grep-Edit") + (buffer-enable-undo) + (set-buffer-modified-p nil) + (setq buffer-undo-list nil) + (add-hook 'after-change-functions #'occur-after-change-function nil t) + (run-mode-hooks 'grep-edit-mode-hook) + (message "Editing: \\[grep-edit-save-changes] to return to Grep mode")) + +(defun grep-edit-save-changes () + "Switch back to Grep mode." + (interactive) + (unless (derived-mode-p 'grep-edit-mode) + (error "Not a Grep-Edit buffer")) + (remove-hook 'after-change-functions #'occur-after-change-function t) + (use-local-map grep-mode-map) + (setq buffer-read-only t) + (setq major-mode 'grep-mode) + (setq mode-name "Grep") + (force-mode-line-update) + (buffer-disable-undo) + (setq buffer-undo-list t) + (message "Switching to Grep mode")) ;;;###autoload (defun grep-find (command-args) --=-=-=--