Subject: Re: bug#64055: [WIP Patch] Enable editing commit messages - vc-git-modify-change-comment

From: Dmitry Gutov <[email-masked]>
Date: Thu, 3 Oct 2024 02:20:56 +0300

On 02/10/2024 03:01, Sean Whitton wrote:
> On Tue 01 Oct 2024 at 10:32pm +03, Dmitry Gutov wrote:
> 
>> On 01/10/2024 05:38, Sean Whitton wrote:
>>> Morgan, Dmitry, you have both posted WIP on this.  Have you made any
>>> progress?  Are you interested in looking at it again?
>> I haven't worked on it, sorry.
>>
>> If my old WIP looks useful, you're quite welcome to use it as a starting
>> point. No need for attribution or anything like that.
> Could you point me at that WIP, please?  It's not posted to this bug and
> I couldn't find it in my mail archives.

Yeah, sorry about that.

Here's the diff I have lying around from back then. Not sure how much it 
will help - the changes in log-view.el seems like an improvement (more 
generic approach), whereas the vc-git-modify-change-comment definition 
might be better in Morgan's patch (it /would/ be nice to be able to edit 
older commits, not just the most recent one).

diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index 054c2b9134..8794ce5d31 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -529,34 +529,18 @@ log-view-find-revision
 					(log-view-current-tag)))))

-(defun log-view-extract-comment ()
-  "Parse comment from around the current point in the log."
-  (save-excursion
-    (let (st en (backend (vc-backend (log-view-current-file))))
-      (log-view-end-of-defun)
-      (cond ((eq backend 'SVN)
-	     (forward-line -1)))
-      (setq en (point))
-      (or (log-view-current-entry nil t)
-          (throw 'beginning-of-buffer nil))
-      (cond ((memq backend '(SCCS RCS CVS SVN))
-	     (forward-line 2))
-	    ((eq backend 'Hg)
-	     (forward-line 4)
-	     (re-search-forward "summary: *" nil t)))
-      (setq st (point))
-      (buffer-substring st en))))
-
 (declare-function vc-modify-change-comment "vc" (files rev oldcomment))
 
 (defun log-view-modify-change-comment ()
   "Edit the change comment displayed at point."
   (interactive)
-  (vc-modify-change-comment (list (if log-view-per-file-logs
-				      (log-view-current-file)
-				    (car log-view-vc-fileset)))
-			    (log-view-current-tag)
-			    (log-view-extract-comment)))
+  (let* ((file (and log-view-per-file-logs
+                    (log-view-current-file)))
+         (revision (log-view-current-tag))
+         (backend (vc-responsible-backend (or file (car log-view-vc-fileset)))))
+    (vc-modify-change-comment (list file)
+                              revision
+                              (vc-call-backend backend 'expanded-log-entry))))
 
 (defun log-view-annotate-version (pos)
   "Annotate the version at POS.
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index ca4c66a06d..d792eeb429 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -950,6 +950,49 @@ vc-git-checkin
 		    (if only (list "--only" "--") '("-a")))))
     (if (and msg-file (file-exists-p msg-file)) (delete-file msg-file))))
 
+(defun vc-git-modify-change-comment (files rev comment)
+  (let* ((file1 (or (car files) default-directory))
+         (root (vc-git-root file1))
+         (default-directory (expand-file-name root))
+         (pcsw coding-system-for-write)
+         (coding-system-for-write
+          ;; On MS-Windows, we must encode command-line arguments in
+          ;; the system codepage.
+          (if (eq system-type 'windows-nt)
+              locale-coding-system
+            (or coding-system-for-write vc-git-commits-coding-system)))
+         (msg-file
+          ;; On MS-Windows, pass the commit log message through a
+          ;; file, to work around the limitation that command-line
+          ;; arguments must be in the system codepage, and therefore
+          ;; might not support the non-ASCII characters in the log
+          ;; message.  Handle also remote files.
+          (if (eq system-type 'windows-nt)
+              (let ((default-directory (file-name-directory file1)))
+                (make-nearby-temp-file "git-msg")))))
+    (cl-flet ((boolean-arg-fn
+               (argument)
+               (lambda (value) (when (equal value "yes") (list argument)))))
+      ;; When operating on the whole tree, better pass "-a" than ".", since "."
+      ;; fails when we're committing a merge.
+      (apply 'vc-git-command nil 0 nil
+             (nconc (if msg-file (list "commit" "-F"
+                                       (file-local-name msg-file))
+                      (list "commit" "-m"))
+                    (let ((args
+                           (log-edit-extract-headers
+                            `(("Author" . "--author")
+                              ("No-Verify" . ,(boolean-arg-fn "--no-verify"))
+                              ("Sign-Off" . ,(boolean-arg-fn "--signoff")))
+                            comment)))
+                      (when msg-file
+                        (let ((coding-system-for-write
+                               (or pcsw vc-git-commits-coding-system)))
+                          (write-region (car args) nil msg-file))
+                        (setq args (cdr args)))
+                      args))))
+    (if (and msg-file (file-exists-p msg-file)) (delete-file msg-file))))
+
 (defun vc-git-find-revision (file rev buffer)
   (let* (process-file-side-effects
 	 (coding-system-for-read 'binary)