+2012-10-01 Dmitry Gutov <dgutov@yandex.ru>
+
+ * vc/vc-git.el (vc-git-log-edit-toggle-signoff): New function.
+ (vc-git-log-edit-toggle-amend): New function.
+ (vc-git-log-edit-toggle-signoff): New function.
+ (vc-git-log-edit-mode): New major mode.
+ (vc-git-log-edit-mode-map): Keymap for it.
+ (vc-git-checkin): Handle "Amend" and "Sign-Off" headers.
+
+ * vc/log-edit.el (log-edit-font-lock-keywords): Allow hyphens in
+ header names.
+ (log-edit-toggle-header): New function.
+ (log-edit-extract-headers): Accept function values in HEADERS alist.
+
2012-10-01 David Engster <deng@randomsample.de>
* emacs-lisp/eieio-opt.el (eieio-describe-class): Add filename
(defvar log-edit-font-lock-keywords
;; Copied/inspired by message-font-lock-keywords.
`((log-edit-match-to-eoh
- (,(concat "^\\(\\([[:alpha:]]+\\):\\)" log-edit-header-contents-regexp)
+ (,(concat "^\\(\\([[:alpha:]-]+\\):\\)" log-edit-header-contents-regexp)
(progn (goto-char (match-beginning 0)) (match-end 0)) nil
(1 (if (assoc-string (match-string 2) log-edit-headers-alist t)
'log-edit-header
(insert "\n"))
log-edit-author))
+(defun log-edit-toggle-header (header value)
+ "Toggle a boolean-type header in the current buffer.
+If the value of HEADER is VALUE, clear it. Otherwise, add the
+header if it's not present and set it to VALUE. Then make sure
+there is an empty line after the headers. Return t if toggled
+on, otherwise nil."
+ (let ((val t)
+ (line (concat header ": " value "\n")))
+ (save-excursion
+ (save-restriction
+ (rfc822-goto-eoh)
+ (narrow-to-region (point-min) (point))
+ (goto-char (point-min))
+ (if (re-search-forward (concat "^" header ":"
+ log-edit-header-contents-regexp)
+ nil t)
+ (if (setq val (not (string= (match-string 1) value)))
+ (replace-match line t t)
+ (replace-match "" t t nil 1))
+ (insert line)))
+ (rfc822-goto-eoh)
+ (delete-horizontal-space)
+ (unless (looking-at "\n")
+ (insert "\n")))
+ val))
+
(defun log-edit-extract-headers (headers comment)
"Extract headers from COMMENT to form command line arguments.
-HEADERS should be an alist with elements of the form (HEADER . CMDARG)
-associating header names to the corresponding cmdline option name and the
-result is then a list of the form (MSG CMDARG1 HDRTEXT1 CMDARG2 HDRTEXT2...).
-where MSG is the remaining text from STRING.
-If \"Summary\" is not in HEADERS, then the \"Summary\" header is extracted
-anyway and put back as the first line of MSG."
+HEADERS should be an alist with elements (HEADER . CMDARG)
+or (HEADER . FUNCTION) associating headers to command line
+options and the result is then a list of the form (MSG ARGUMENTS...)
+where MSG is the remaining text from COMMENT.
+FUNCTION should be a function of one argument that takes the
+header value and returns the list of strings to be appended to
+ARGUMENTS. CMDARG will be added to ARGUMENTS followed by the
+header value. If \"Summary\" is not in HEADERS, then the
+\"Summary\" header is extracted anyway and put back as the first
+line of MSG."
(with-temp-buffer
(insert comment)
(rfc822-goto-eoh)
nil t)
(if (eq t (cdr header))
(setq summary (match-string 1))
- (push (match-string 1) res)
- (push (or (cdr header) (car header)) res))
+ (if (functionp (cdr header))
+ (setq res (nconc res (funcall (cdr header) (match-string 1))))
+ (push (match-string 1) res)
+ (push (or (cdr header) (car header)) res)))
(replace-match "" t t)))
;; Remove header separator if the header is empty.
(widen)
(defun vc-git-unregister (file)
(vc-git-command nil 0 file "rm" "-f" "--cached" "--"))
+(declare-function log-edit-mode "log-edit" ())
+(declare-function log-edit-toggle-header "log-edit" (header value))
(declare-function log-edit-extract-headers "log-edit" (headers string))
+(defun vc-git-log-edit-toggle-signoff ()
+ "Toggle whether to add the \"Signed-off-by\" line at the end of
+the commit message."
+ (interactive)
+ (log-edit-toggle-header "Sign-Off" "yes"))
+
+(defun 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")))))
+
+(defvar vc-git-log-edit-mode-map
+ (let ((map (make-sparse-keymap "Git-Log-Edit")))
+ (define-key map "\C-c\C-s" 'vc-git-log-edit-toggle-signoff)
+ (define-key map "\C-c\C-e" 'vc-git-log-edit-toggle-amend)
+ map))
+
+(define-derived-mode vc-git-log-edit-mode log-edit-mode "Log-Edit/git"
+ "Major mode for editing Git log messages.
+It is based on `log-edit-mode', and has Git-specific extensions.")
+
(defun vc-git-checkin (files _rev comment)
(let ((coding-system-for-write vc-git-commits-coding-system))
- (apply 'vc-git-command nil 0 files
- (nconc (list "commit" "-m")
- (log-edit-extract-headers '(("Author" . "--author")
- ("Date" . "--date"))
- comment)
- (list "--only" "--")))))
+ (cl-flet ((boolean-arg-fn
+ (argument)
+ (lambda (value) (when (equal value "yes") (list argument)))))
+ (apply 'vc-git-command nil 0 files
+ (nconc (list "commit" "-m")
+ (log-edit-extract-headers
+ `(("Author" . "--author")
+ ("Date" . "--date")
+ ("Amend" . ,(boolean-arg-fn "--amend"))
+ ("Sign-Off" . ,(boolean-arg-fn "--signoff")))
+ comment)
+ (list "--only" "--"))))))
(defun vc-git-find-revision (file rev buffer)
(let* (process-file-side-effects