Keyword added and FSF specified as Maintainer.
[bpt/emacs.git] / lisp / add-log.el
index a89cbd4..61a29be 100644 (file)
@@ -2,6 +2,7 @@
 
 ;; Copyright (C) 1985, 86, 88, 93, 94, 97, 98, 2000 Free Software Foundation, Inc.
 
+;; Maintainer: FSF
 ;; Keywords: tools
 
 ;; This file is part of GNU Emacs.
@@ -53,7 +54,7 @@
   "*If non-nil, function to guess name of surrounding function.
 It is used by `add-log-current-defun' in preference to built-in rules.
 Returns function's name as a string, or nil if outside a function."
-  :type 'function
+  :type '(choice (const nil) function)
   :group 'change-log)
 
 ;;;###autoload
@@ -116,12 +117,19 @@ this variable."
   :type 'boolean
   :group 'change-log)
 
+(defcustom add-log-buffer-file-name-function nil
+  "*If non-nil, function to call to identify the full filename of a buffer.
+This function is called with no argument.  If this is nil, the default is to
+use `buffer-file-name'."
+  :type '(choice (const nil) function)
+  :group 'change-log)
+
 (defcustom add-log-file-name-function nil
   "*If non-nil, function to call to identify the filename for a ChangeLog entry.
 This function is called with one argument, the value of variable
 `buffer-file-name' in that buffer.  If this is nil, the default is to
 use the file's name relative to the directory of the change log file."
-  :type 'function
+  :type '(choice (const nil) function)
   :group 'change-log)
 
 
@@ -145,39 +153,87 @@ Note: The search is conducted only within 10%, at the beginning of the file."
   :type '(repeat regexp)
   :group 'change-log)
 
+(defface change-log-date-face
+  '((t (:inherit font-lock-string-face)))
+  "Face used to highlight dates in date lines."
+  :version "21.1"
+  :group 'change-log)
+
+(defface change-log-name-face
+  '((t (:inherit font-lock-constant-face)))
+  "Face for highlighting author names."
+  :version "21.1"
+  :group 'change-log)
+
+(defface change-log-email-face
+  '((t (:inherit font-lock-variable-name-face)))
+  "Face for highlighting author email addresses."
+  :version "21.1"
+  :group 'change-log)
+
+(defface change-log-file-face
+  '((t (:inherit font-lock-function-name-face)))
+  "Face for highlighting file names."
+  :version "21.1"
+  :group 'change-log)
+
+(defface change-log-list-face
+  '((t (:inherit font-lock-keyword-face)))
+  "Face for highlighting parenthesized lists of functions or variables."
+  :version "21.1"
+  :group 'change-log)
+  
+(defface change-log-conditionals-face
+  '((t (:inherit font-lock-variable-name-face)))
+  "Face for highlighting conditionals of the form `[...]'."
+  :version "21.1"
+  :group 'change-log)
+
+(defface change-log-function-face
+  '((t (:inherit font-lock-variable-name-face)))
+  "Face for highlighting items of the form `<....>'."
+  :version "21.1"
+  :group 'change-log)
+
+(defface change-log-acknowledgement-face
+  '((t (:inherit font-lock-comment-face)))
+  "Face for highlighting acknowledgments."
+  :version "21.1"
+  :group 'change-log)
 
 (defvar change-log-font-lock-keywords
   '(;;
     ;; Date lines, new and old styles.
     ("^\\sw.........[0-9:+ ]*"
-     (0 font-lock-string-face)
+     (0 'change-log-date-face)
      ;; Name and e-mail; some people put e-mail in parens, not angles.
-     ("\\([^<(]+\\)[(<]\\([A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+\\)[>)]" nil nil
-      (1 font-lock-constant-face)
-      (2 font-lock-variable-name-face)))
+     ("\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+\\)[>)]" nil nil
+      (1 'change-log-name-face)
+      (2 'change-log-email-face)))
     ;;
     ;; File names.
     ("^\t\\* \\([^ ,:([\n]+\\)"
-     (1 font-lock-function-name-face)
+     (1 'change-log-file-face)
      ;; Possibly further names in a list:
-     ("\\=, \\([^ ,:([\n]+\\)" nil nil (1 font-lock-function-name-face))
+     ("\\=, \\([^ ,:([\n]+\\)" nil nil (1 'change-log-file-face))
      ;; Possibly a parenthesized list of names:
-     ("\\= (\\([^) ,:\n]+\\)" nil nil (1 font-lock-keyword-face))
-     ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 font-lock-keyword-face)))
+     ("\\= (\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face))
+     ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face)))
     ;;
     ;; Function or variable names.
     ("^\t(\\([^) ,:\n]+\\)"
-     (1 font-lock-keyword-face)
-     ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 font-lock-keyword-face)))
+     (1 'change-log-list-face)
+     ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face)))
     ;;
     ;; Conditionals.
-    ("\\[!?\\([^]\n]+\\)\\]\\(:\\| (\\)" (1 font-lock-variable-name-face))
+    ("\\[!?\\([^]\n]+\\)\\]\\(:\\| (\\)" (1 'change-log-conditionals-face))
+    ;;
+    ;; Function of change.
+    ("<\\([^>\n]+\\)>\\(:\\| (\\)" (1 'change-log-function-face))
     ;;
     ;; Acknowledgements.
-    ("^\t\\(From\\|Patch\\(es\\)? by\\|Report\\(ed by\\| from\\)\\|Suggest\\(ed by\\|ion from\\)\\)"
-     1 font-lock-comment-face)
-    ("  \\(From\\|Patch\\(es\\)? by\\|Report\\(ed by\\| from\\)\\|Suggest\\(ed by\\|ion from\\)\\)"
-     1 font-lock-comment-face))
+    ("\\(^\t\\|  \\)\\(From\\|Patch\\(es\\)? by\\|Report\\(ed by\\| from\\)\\|Suggest\\(ed by\\|ion from\\)\\)"
+     2 'change-log-acknowledgement-face))
   "Additional expressions to highlight in Change Log mode.")
 
 (defvar change-log-mode-map (make-sparse-keymap)
@@ -207,8 +263,7 @@ If nil, use local time.")
            (now (current-time)))
        (unwind-protect
            (progn
-             (set-time-zone-rule
-              change-log-time-zone-rule)
+             (set-time-zone-rule change-log-time-zone-rule)
              (concat
               (format-time-string "%Y-%m-%d " now)
               (add-log-iso8601-time-zone now)))
@@ -256,8 +311,7 @@ nil, by matching `change-log-version-number-regexp-list'."
              (/ size 10)
            size))
         version)
-    (or (and buffer-file-name
-            (vc-workfile-version buffer-file-name))
+    (or (and buffer-file-name (vc-workfile-version buffer-file-name))
        (save-restriction
          (widen)
          (let ((regexps change-log-version-number-regexp-list))
@@ -270,7 +324,7 @@ nil, by matching `change-log-version-number-regexp-list'."
 
 
 ;;;###autoload
-(defun find-change-log (&optional file-name)
+(defun find-change-log (&optional file-name buffer-file)
   "Find a change log file for \\[add-change-log-entry] and return the name.
 
 Optional arg FILE-NAME specifies the file to use.
@@ -283,7 +337,8 @@ simply find it in the current directory.  Otherwise, search in the current
 directory and its successive parents for a file so named.
 
 Once a file is found, `change-log-default-name' is set locally in the
-current buffer to the complete file name."
+current buffer to the complete file name.
+Optional arg BUFFER-FILE overrides `buffer-file-name'."
   ;; If user specified a file name or if this buffer knows which one to use,
   ;; just use that.
   (or file-name
@@ -293,9 +348,10 @@ current buffer to the complete file name."
       (progn
        ;; Chase links in the source file
        ;; and use the change log in the dir where it points.
-       (setq file-name (or (and buffer-file-name
+       (setq file-name (or (and (or buffer-file buffer-file-name)
                                 (file-name-directory
-                                 (file-chase-links buffer-file-name)))
+                                 (file-chase-links
+                                  (or buffer-file buffer-file-name))))
                            default-directory))
        (if (file-directory-p file-name)
            (setq file-name (expand-file-name (change-log-name) file-name)))
@@ -326,6 +382,24 @@ current buffer to the complete file name."
   (set (make-local-variable 'change-log-default-name) file-name)
   file-name)
 
+(defun add-log-file-name (buffer-file log-file)
+  ;; Never want to add a change log entry for the ChangeLog file itself.
+  (unless (or (null buffer-file) (string= buffer-file log-file))
+    (if add-log-file-name-function
+       (funcall add-log-file-name-function buffer-file)
+      (setq buffer-file
+           (if (string-match
+                (concat "^" (regexp-quote (file-name-directory log-file)))
+                buffer-file)
+               (substring buffer-file (match-end 0))
+             (file-name-nondirectory buffer-file)))
+      ;; If we have a backup file, it's presumably because we're
+      ;; comparing old and new versions (e.g. for deleted
+      ;; functions) and we'll want to use the original name.
+      (if (backup-file-name-p buffer-file)
+         (file-name-sans-versions buffer-file)
+       buffer-file))))
+
 ;;;###autoload
 (defun add-change-log-entry (&optional whoami file-name other-window new-entry)
   "Find change log file and add an entry for today.
@@ -355,34 +429,22 @@ non-nil, otherwise in local time."
         ;; s/he can edit the full name field in prompter if s/he wants.
        (setq add-log-mailing-address
              (read-input "Mailing address: " add-log-mailing-address))))
-  (let ((defun (add-log-current-defun))
-       (version (and change-log-version-info-enabled
-                     (change-log-version-number-search)))
-       bound entry)
-
-    (setq file-name (expand-file-name (find-change-log file-name)))
-
-    ;; Set ENTRY to the file name to use in the new entry.
-    (and buffer-file-name
-        ;; Never want to add a change log entry for the ChangeLog file itself.
-        (not (string= buffer-file-name file-name))
-        (if add-log-file-name-function
-            (setq entry
-                  (funcall add-log-file-name-function buffer-file-name))
-          (setq entry
-                (if (string-match
-                     (concat "^" (regexp-quote (file-name-directory
-                                                file-name)))
-                     buffer-file-name)
-                    (substring buffer-file-name (match-end 0))
-                  (file-name-nondirectory buffer-file-name)))
-          ;; If we have a backup file, it's presumably because we're
-          ;; comparing old and new versions (e.g. for deleted
-          ;; functions) and we'll want to use the original name.
-          (if (backup-file-name-p entry)
-              (setq entry (file-name-sans-versions entry)))))
-
-    (if (and other-window (not (equal file-name buffer-file-name)))
+
+  (let* ((defun (add-log-current-defun))
+        (version (and change-log-version-info-enabled
+                      (change-log-version-number-search)))
+        (buf-file-name (if add-log-buffer-file-name-function
+                           (funcall add-log-buffer-file-name-function)
+                         buffer-file-name))
+        (buffer-file (if buf-file-name (expand-file-name buf-file-name)))
+        (file-name (expand-file-name
+                    (or file-name (find-change-log file-name buffer-file))))
+        ;; Set ENTRY to the file name to use in the new entry.
+        (entry (add-log-file-name buffer-file file-name))
+        bound)
+
+    (if (or (and other-window (not (equal file-name buffer-file-name)))
+           (window-dedicated-p (selected-window)))
        (find-file-other-window file-name)
       (find-file file-name))
     (or (eq major-mode 'change-log-mode)
@@ -424,7 +486,7 @@ non-nil, otherwise in local time."
           ;; Delete excess empty lines; make just 2.
           (while (and (not (eobp)) (looking-at "^\\s *$"))
             (delete-region (point) (line-beginning-position 2)))
-          (insert "\n\n")
+          (insert-char ?\n 2)
           (forward-line -2)
           (indent-relative-maybe))
          (t
@@ -434,10 +496,11 @@ non-nil, otherwise in local time."
             (forward-line 1))
           (while (and (not (eobp)) (looking-at "^\\s *$"))
             (delete-region (point) (line-beginning-position 2)))
-          (insert "\n\n\n")
+          (insert-char ?\n 3)
           (forward-line -2)
           (indent-to left-margin)
-          (insert "* " (or entry ""))))
+          (insert "* ")
+          (if entry (insert entry))))
     ;; Now insert the function name, if we have one.
     ;; Point is at the entry for this file,
     ;; either at the end of the line or at the first blank line.
@@ -449,7 +512,20 @@ non-nil, otherwise in local time."
                    (beginning-of-line 1)
                    (looking-at "\\s *$"))
            (insert ?\ ))
-         (insert "(" defun "): ")
+         ;; See if the prev function name has a message yet or not
+         ;; If not, merge the two entries.
+         (let ((pos (point-marker)))
+           (if (and (skip-syntax-backward " ")
+                    (skip-chars-backward "):")
+                    (looking-at "):")
+                    (progn (delete-region (+ 1 (point)) (+ 2 (point))) t)
+                    (> fill-column (+ (current-column) (length defun) 3)))
+               (progn (delete-region (point) pos)
+                      (insert ", "))
+             (goto-char pos)
+             (insert "("))
+           (set-marker pos nil))
+         (insert defun "): ")
          (if version
              (insert version ?\ )))
       ;; No function name, so put in a colon unless we have just a star.
@@ -505,7 +581,7 @@ Runs `change-log-mode-hook'."
   (set (make-local-variable 'version-control) 'never)
   (set (make-local-variable 'adaptive-fill-regexp) "\\s *")
   (set (make-local-variable 'font-lock-defaults)
-       '(change-log-font-lock-keywords t))
+       '(change-log-font-lock-keywords t nil nil backward-paragraph))
   (run-hooks 'change-log-mode-hook))
 
 ;; It might be nice to have a general feature to replace this.  The idea I
@@ -523,7 +599,7 @@ Prefix arg means justify as well."
     t))
 \f
 (defcustom add-log-current-defun-header-regexp
-  "^\\([A-Z][A-Z_ ]*[A-Z_]\\|[-_a-zA-Z]+\\)[ \t]*[:=]"
+  "^\\([[:upper:]][[:upper:]_ ]*[[:upper:]_]\\|[-_[:alpha:]]+\\)[ \t]*[:=]"
   "*Heuristic regexp used by `add-log-current-defun' for unknown major modes."
   :type 'regexp
   :group 'change-log)
@@ -719,7 +795,7 @@ Has a preference of looking backwards."
                ((eq major-mode 'texinfo-mode)
                 (if (re-search-backward "^@node[ \t]+\\([^,\n]+\\)" nil t)
                     (match-string-no-properties 1)))
-               ((eq major-mode 'perl-mode)
+               ((memq major-mode '(perl-mode cperl-mode))
                 (if (re-search-backward "^sub[ \t]+\\([^ \t\n]+\\)" nil t)
                     (match-string-no-properties 1)))
                ;; Emacs's autoconf-mode installs its own
@@ -797,11 +873,8 @@ Point is assumed to be at the start of the entry."
 Both must be found in Change Log mode (since the merging depends on
 the appropriate motion commands).
 
-Entries are inserted in chronological order.
-
-Both the current and old-style time formats for entries are supported,
-so this command could be used to convert old-style logs by merging
-with an empty log."
+Entries are inserted in chronological order.  Both the current and
+old-style time formats for entries are supported."
   (interactive "*fLog file name to merge: ")
   (if (not (eq major-mode 'change-log-mode))
       (error "Not in Change Log mode"))
@@ -835,6 +908,29 @@ with an empty log."
                                       (goto-char (point-max))
                                       (point)))))))))
 
+;;;###autoload
+(defun change-log-redate ()
+  "Fix any old-style date entries in the current log file to default format."
+  (interactive)
+  (require 'timezone)
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "^\\sw.........[0-9:+ ]*" nil t)
+      (unless (= 12 (- (match-end 0) (match-beginning 0)))
+       (let* ((date (save-match-data
+                      (timezone-fix-time (match-string 0) nil nil)))
+              (zone (if (consp (aref date 6))
+                        (nth 1 (aref date 6)))))
+         (replace-match (format-time-string
+                         "%Y-%m-%d  "
+                         (encode-time (aref date 5)
+                                      (aref date 4)
+                                      (aref date 3)
+                                      (aref date 2)
+                                      (aref date 1)
+                                      (aref date 0)
+                                      zone))))))))
+
 (provide 'add-log)
 
 ;;; add-log.el ends here