Subject: Re: bug#34944: 27.0.50; FR: support amend in vc-hg

From: Dmitry Gutov <[email-masked]>
Date: Wed, 3 Apr 2019 03:33:12 +0300

On 22.03.2019 12:44, Philipp Stephani wrote:
> 
> The Git integration for vc.el supports amending commits via a magic
> changelog header.  Mercurial has the same functionality, see
> https://www.mercurial-scm.org/wiki/EditingHistory#Amending_the_latest_changeset_with_commit_--amend.
> If would be great to support this in Emacs as well.  Maybe the Git
> approach could even move into main VC, and made available to all
> backends that support amending?

Here's a patch you can try (attached).

No backend API change necessary, so far.

Are there many backends that could support amending?
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index a921ff1bb8..6ce3ccde1e 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -767,23 +767,12 @@ vc-git-log-edit-toggle-amend
   "Toggle whether this will amend the previous commit.
 If toggling on, also insert its message into the buffer."
   (interactive)
-  (when (log-edit-toggle-header "Amend" "yes")
-    (goto-char (point-max))
-    (unless (bolp) (insert "\n"))
-    (insert (with-output-to-string
-              (vc-git-command
-               standard-output 1 nil
-               "log" "--max-count=1" "--pretty=format:%B" "HEAD")))
-    (save-excursion
-      (rfc822-goto-eoh)
-      (forward-line 1)
-      (let ((pt (point)))
-        (and (zerop (forward-line 1))
-             (looking-at "\n\\|\\'")
-             (let ((summary (buffer-substring-no-properties pt (1- (point)))))
-               (skip-chars-forward " \n")
-               (delete-region pt (point))
-               (log-edit-set-header "Summary" summary)))))))
+  (vc--log-edit-toggle-amend
+   (lambda ()
+     (with-output-to-string
+       (vc-git-command
+        standard-output 1 nil
+        "log" "--max-count=1" "--pretty=format:%B" "HEAD")))))
 
 (defvar vc-git-log-edit-mode-map
   (let ((map (make-sparse-keymap "Git-Log-Edit")))
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 6b17e861dd..9dedfa5744 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -1105,14 +1105,39 @@ vc-hg-unregister
 
 (declare-function log-edit-extract-headers "log-edit" (headers string))
 
+(defun vc-hg-log-edit-toggle-amend ()
+  "Toggle whether this will amend the previous commit.
+If toggling on, also insert its message into the buffer."
+  (interactive)
+  (vc--log-edit-toggle-amend
+   (lambda ()
+     (with-output-to-string
+       (vc-hg-command
+        standard-output 1 nil
+        "log" "--limit=1" "--template" "{desc}")))))
+
+(defvar vc-hg-log-edit-mode-map
+  (let ((map (make-sparse-keymap "Hg-Log-Edit")))
+    (define-key map "\C-c\C-e" 'vc-hg-log-edit-toggle-amend)
+    map))
+
+(define-derived-mode vc-hg-log-edit-mode log-edit-mode "Log-Edit/hg"
+  "Major mode for editing Hg log messages.
+It is based on `log-edit-mode', and has Hg-specific extensions.")
+
 (defun vc-hg-checkin (files comment &optional _rev)
   "Hg-specific version of `vc-backend-checkin'.
 REV is ignored."
-  (apply 'vc-hg-command nil 0 files
-         (nconc (list "commit" "-m")
-                (log-edit-extract-headers '(("Author" . "--user")
-					    ("Date" . "--date"))
-                                          comment))))
+  (let ((amend-extract-fn
+         (lambda (value)
+           (when (equal value "yes")
+             (list "--amend")))))
+    (apply 'vc-hg-command nil 0 files
+           (nconc (list "commit" "-m")
+                  (log-edit-extract-headers `(("Author" . "--user")
+                                              ("Date" . "--date")
+                                              ("Amend" . ,amend-extract-fn))
+                                            comment)))))
 
 (defun vc-hg-find-revision (file rev buffer)
   (let ((coding-system-for-read 'binary)
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index e6f30c9f80..3ae0ad663e 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -3045,6 +3045,22 @@ vc-check-headers
   (interactive)
   (vc-call-backend (vc-backend buffer-file-name) 'check-headers))
 
+(defun vc--log-edit-toggle-amend (last-msg-fn)
+  (when (log-edit-toggle-header "Amend" "yes")
+    (goto-char (point-max))
+    (unless (bolp) (insert "\n"))
+    (insert (funcall last-msg-fn))
+    (save-excursion
+      (rfc822-goto-eoh)
+      (forward-line 1)
+      (let ((pt (point)))
+        (and (zerop (forward-line 1))
+             (looking-at "\n\\|\\'")
+             (let ((summary (buffer-substring-no-properties pt (1- (point)))))
+               (skip-chars-forward " \n")
+               (delete-region pt (point))
+               (log-edit-set-header "Summary" summary)))))))
+
 
 
 ;; These things should probably be generally available