Update docstrings for last change.
[bpt/emacs.git] / lisp / vc / log-edit.el
index 64cfa20..7ee000a 100644 (file)
@@ -1,7 +1,6 @@
-;;; log-edit.el --- Major mode for editing CVS commit messages
+;;; log-edit.el --- Major mode for editing CVS commit messages -*- lexical-binding: t -*-
 
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;;   2008, 2009, 2010, 2011  Free Software Foundation, Inc.
+;; Copyright (C) 1999-2012  Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: pcl-cvs cvs commit log vc
@@ -30,7 +29,6 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
 (require 'add-log)                     ; for all the ChangeLog goodies
 (require 'pcvs-util)
 (require 'ring)
@@ -162,7 +160,7 @@ can be obtained from `log-edit-files'."
                        "21.1")
 
 (defvar log-edit-changelog-full-paragraphs cvs-changelog-full-paragraphs
-  "*If non-nil, include full ChangeLog paragraphs in the log.
+  "If non-nil, include full ChangeLog paragraphs in the log.
 This may be set in the ``local variables'' section of a ChangeLog, to
 indicate the policy for that ChangeLog.
 
@@ -192,11 +190,17 @@ when this variable is set to nil.")
 
 (defvar log-edit-parent-buffer nil)
 
+(defvar log-edit-vc-backend nil
+  "VC fileset corresponding to the current log.")
+
 ;;; Originally taken from VC-Log mode
 
 (defconst log-edit-maximum-comment-ring-size 32
   "Maximum number of saved comments in the comment ring.")
+(define-obsolete-variable-alias 'vc-comment-ring 'log-edit-comment-ring "22.1")
 (defvar log-edit-comment-ring (make-ring log-edit-maximum-comment-ring-size))
+(define-obsolete-variable-alias 'vc-comment-ring-index
+  'log-edit-comment-ring-index "22.1")
 (defvar log-edit-comment-ring-index nil)
 (defvar log-edit-last-comment-match "")
 
@@ -302,8 +306,6 @@ automatically."
        (insert "\n"))))
 
 ;; Compatibility with old names.
-(define-obsolete-variable-alias 'vc-comment-ring 'log-edit-comment-ring "22.1")
-(define-obsolete-variable-alias 'vc-comment-ring-index 'log-edit-comment-ring-index "22.1")
 (define-obsolete-function-alias 'vc-previous-comment 'log-edit-previous-comment "22.1")
 (define-obsolete-function-alias 'vc-next-comment 'log-edit-next-comment "22.1")
 (define-obsolete-function-alias 'vc-comment-search-reverse 'log-edit-comment-search-backward "22.1")
@@ -330,7 +332,7 @@ automatically."
 (defconst log-edit-header-contents-regexp
   "[ \t]*\\(.*\\(\n[ \t].*\\)*\\)\n?")
 
-(defun log-edit-match-to-eoh (limit)
+(defun log-edit-match-to-eoh (_limit)
   ;; FIXME: copied from message-match-to-eoh.
   (let ((start (point)))
     (rfc822-goto-eoh)
@@ -350,7 +352,7 @@ automatically."
 (defvar log-edit-font-lock-keywords
   ;; Copied/inspired by message-font-lock-keywords.
   `((log-edit-match-to-eoh
-     (,(concat "^\\(\\([a-z]+\\):\\)" 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 (match-string 2) log-edit-headers-alist)
              'log-edit-header
@@ -361,33 +363,79 @@ automatically."
              'log-edit-header)
          nil lax)))))
 
+(defvar log-edit-font-lock-gnu-style nil
+  "If non-nil, highlight common failures to follow the GNU coding standards.")
+(put 'log-edit-font-lock-gnu-style 'safe-local-variable 'booleanp)
+
+(defconst log-edit-font-lock-gnu-keywords
+    ;; Use
+    ;;   * foo.el (bla, bli)
+    ;;   (blo, blu): Toto.
+    ;; Rather than
+    ;;   * foo.el (bla, bli,
+    ;;   blo, blu): Toto.
+  '(("^[ \t]*\\(?:\\* .*\\)?\\(([^\n)]*,\\s-*\\)$"
+     (1 '(face font-lock-warning-face
+          help-echo "Continue function lists with \")\\n(\".") t))
+    ;; Don't leave a lone word on a single line.
+    ;;("^\\s-*\\(\\S-*[^\n:)]\\)\\s-*$" (1 font-lock-warning-face t))
+    ;; Don't cut a sentence right after the first word (better to move
+    ;; the sentence on the next line, then).
+    ;;("[.:]\\s-+\\(\\sw+\\)\\s-*$" (1 font-lock-warning-face t))
+    ;; Change Log entries should use present tense.
+    ("):[ \t\n]*[[:alpha:]]+\\(ed\\)\\>"
+     (1 '(face font-lock-warning-face help-echo "Use present tense.") t))
+    ;; Change log entries start with a capital letter.
+    ("): [a-z]" (0 '(face font-lock-warning-face help-echo "Capitalize.") t))
+    ("[^[:upper:]]\\(\\. [[:upper:]]\\)"
+     (1 '(face font-lock-warning-face
+          help-echo "Use two spaces to end a sentence") t))
+    ("^("
+     (0 (let ((beg (max (point-min) (- (match-beginning 0) 2))))
+          (put-text-property beg (match-end 0) 'font-lock-multiline t)
+          (if (eq (char-syntax (char-after beg)) ?w)
+              '(face font-lock-warning-face
+                help-echo "Punctuate previous line.")))
+        t))
+    ))
+
+(defun log-edit-font-lock-keywords ()
+  (if log-edit-font-lock-gnu-style
+      (append log-edit-font-lock-keywords
+              log-edit-font-lock-gnu-keywords)
+    log-edit-font-lock-keywords))
+
 ;;;###autoload
-(defun log-edit (callback &optional setup params buffer mode &rest ignore)
+(defun log-edit (callback &optional setup params buffer mode &rest _ignore)
   "Setup a buffer to enter a log message.
-\\<log-edit-mode-map>The buffer will be put in mode MODE or `log-edit-mode'
-if MODE is nil.
-If SETUP is non-nil, the buffer is then erased and `log-edit-hook' is run.
-Mark and point will be set around the entire contents of the buffer so
-that it is easy to kill the contents of the buffer with \\[kill-region].
-Once you're done editing the message, pressing \\[log-edit-done] will call
-`log-edit-done' which will end up calling CALLBACK to do the actual commit.
-
-PARAMS if non-nil is an alist.  Possible keys and associated values:
+The buffer is put in mode MODE or `log-edit-mode' if MODE is nil.
+\\<log-edit-mode-map>
+If SETUP is non-nil, erase the buffer and run `log-edit-hook'.
+Set mark and point around the entire contents of the buffer, so
+that it is easy to kill the contents of the buffer with
+\\[kill-region].  Once the user is done editing the message,
+invoking the command \\[log-edit-done] (`log-edit-done') will
+call CALLBACK to do the actual commit.
+
+PARAMS if non-nil is an alist of variables and buffer-local
+values to give them in the Log Edit buffer.  Possible keys and
+associated values:
  `log-edit-listfun' -- function taking no arguments that returns the list of
  files that are concerned by the current operation (using relative names);
  `log-edit-diff-function' -- function taking no arguments that
  displays a diff of the files concerned by the current operation.
+ `vc-log-fileset' -- the VC fileset to be committed (if any).
 
-If BUFFER is non-nil `log-edit' will jump to that buffer, use it to edit the
-log message and go back to the current buffer when done.  Otherwise, it
-uses the current buffer."
+If BUFFER is non-nil `log-edit' will jump to that buffer, use it
+to edit the log message and go back to the current buffer when
+done.  Otherwise, it uses the current buffer."
   (let ((parent (current-buffer)))
     (if buffer (pop-to-buffer buffer))
     (when (and log-edit-setup-invert (not (eq setup 'force)))
       (setq setup (not setup)))
     (when setup
       (erase-buffer)
-      (insert "Summary: ")
+      (insert "Summary: \nAuthor: ")
       (save-excursion (insert "\n\n")))
     (if mode
        (funcall mode)
@@ -417,7 +465,7 @@ commands (under C-x v for VC, for example).
 
 \\{log-edit-mode-map}"
   (set (make-local-variable 'font-lock-defaults)
-       '(log-edit-font-lock-keywords t t))
+       '(log-edit-font-lock-keywords t))
   (make-local-variable 'log-edit-comment-ring-index)
   (hack-dir-local-variables-non-file-buffer))
 
@@ -532,13 +580,25 @@ If you want to abort the commit, simply delete the buffer."
        (shrink-window-if-larger-than-buffer)
        (selected-window)))))
 
+(defun log-edit-empty-buffer-p ()
+  "Return non-nil if the buffer is \"empty\"."
+  (or (= (point-min) (point-max))
+      (save-excursion
+        (goto-char (point-min))
+        (while (and (looking-at "^\\([a-zA-Z]+: \\)?$")
+                    (zerop (forward-line 1))))
+        (eobp))))
+
 (defun log-edit-insert-cvs-template ()
   "Insert the template specified by the CVS administrator, if any.
 This simply uses the local CVS/Template file."
   (interactive)
   (when (or (called-interactively-p 'interactive)
-           (= (point-min) (point-max)))
+            (log-edit-empty-buffer-p))
+    ;; Should the template take precedence over an empty Summary:,
+    ;; ie should we first erase the buffer?
     (when (file-readable-p "CVS/Template")
+      (goto-char (point-max))
       (insert-file-contents "CVS/Template"))))
 
 (defun log-edit-insert-cvs-rcstemplate ()
@@ -547,8 +607,9 @@ This contacts the repository to get the rcstemplate file and
 can thus take some time."
   (interactive)
   (when (or (called-interactively-p 'interactive)
-           (= (point-min) (point-max)))
+            (log-edit-empty-buffer-p))
     (when (file-readable-p "CVS/Root")
+      (goto-char (point-max))
       ;; Ignore the stderr stuff, even if it's an error.
       (call-process "cvs" nil '(t nil) nil
                     "checkout" "-p" "CVSROOT/rcstemplate"))))
@@ -581,6 +642,13 @@ to build the Fixes: header.")
 (put 'log-edit-rewrite-fixes 'safe-local-variable
      (lambda (v) (and (stringp (car-safe v)) (stringp (cdr v)))))
 
+(defun log-edit-add-field (field value)
+  (rfc822-goto-eoh)
+  (if (save-excursion (re-search-backward (concat "^" field ":\\([ \t]*\\)$")
+                                          nil t))
+      (replace-match (concat " " value) t t nil 1)
+    (insert field ": " value "\n" (if (looking-at "\n") "" "\n"))))
+
 (defun log-edit-insert-changelog (&optional use-first)
   "Insert a log message by looking at the ChangeLog.
 The idea is to write your ChangeLog entries first, and then use this
@@ -608,9 +676,7 @@ regardless of user name or time."
            (log-edit-insert-changelog-entries (log-edit-files)))))
     (log-edit-set-common-indentation)
     ;; Add an Author: field if appropriate.
-    (when author
-      (rfc822-goto-eoh)
-      (insert "Author: " author "\n" (if (looking-at "\n") "" "\n")))
+    (when author (log-edit-add-field "Author" author))
     ;; Add a Fixes: field if applicable.
     (when (consp log-edit-rewrite-fixes)
       (rfc822-goto-eoh)
@@ -620,16 +686,19 @@ regardless of user name or time."
               (fixes (match-substitute-replacement
                       (cdr log-edit-rewrite-fixes))))
           (delete-region start end)
-          (rfc822-goto-eoh)
-          (insert "Fixes: " fixes "\n" (if (looking-at "\n") "" "\n")))))
-    (goto-char (point-min))
-    (when (and log-edit-strip-single-file-name (looking-at "\\*\\s-+"))
-      (forward-line 1)
-      (when (not (re-search-forward "^\\*\\s-+" nil t))
-        (goto-char (point-min))
-        (skip-chars-forward "^():")
-        (skip-chars-forward ": ")
-        (delete-region (point-min) (point))))))
+          (log-edit-add-field "Fixes" fixes))))
+    (and log-edit-strip-single-file-name
+         (progn (rfc822-goto-eoh)
+                (if (looking-at "\n") (forward-char 1))
+                (looking-at "\\*\\s-+"))
+         (let ((start (point)))
+           (forward-line 1)
+           (when (not (re-search-forward "^\\*\\s-+" nil t))
+             (goto-char start)
+             (skip-chars-forward "^():")
+             (skip-chars-forward ": ")
+             (delete-region start (point)))))
+    (goto-char (point-min))))
 
 ;;;;
 ;;;; functions for getting commit message from ChangeLog a file...