(define-minor-mode): A nil argument to the minor mode turns the mode ON.
[bpt/emacs.git] / lisp / add-log.el
index 98aa910..ab99f67 100644 (file)
@@ -1,7 +1,8 @@
 ;;; add-log.el --- change log maintenance commands for Emacs
 
 ;; Copyright (C) 1985, 1986, 1988, 1993, 1994, 1997, 1998, 2000, 2001,
-;;   2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: tools
@@ -162,7 +163,7 @@ use the file's name relative to the directory of the change log file."
   :group 'change-log)
 
 (defcustom change-log-version-number-regexp-list
-  (let ((re    "\\([0-9]+\.[0-9.]+\\)"))
+  (let ((re "\\([0-9]+\.[0-9.]+\\)"))
     (list
      ;;  (defconst ad-version "2.15"
      (concat "^(def[^ \t\n]+[ \t]+[^ \t\n][ \t]\"" re)
@@ -180,64 +181,59 @@ Note: The search is conducted only within 10%, at the beginning of the file."
   "Face used to highlight dates in date lines."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-date-face 'face-alias 'change-log-date)
+(define-obsolete-face-alias 'change-log-date-face 'change-log-date "22.1")
 
 (defface change-log-name
   '((t (:inherit font-lock-constant-face)))
   "Face for highlighting author names."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-name-face 'face-alias 'change-log-name)
+(define-obsolete-face-alias 'change-log-name-face 'change-log-name "22.1")
 
 (defface change-log-email
   '((t (:inherit font-lock-variable-name-face)))
   "Face for highlighting author email addresses."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-email-face 'face-alias 'change-log-email)
+(define-obsolete-face-alias 'change-log-email-face 'change-log-email "22.1")
 
 (defface change-log-file
   '((t (:inherit font-lock-function-name-face)))
   "Face for highlighting file names."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-file-face 'face-alias 'change-log-file)
+(define-obsolete-face-alias 'change-log-file-face 'change-log-file "22.1")
 
 (defface change-log-list
   '((t (:inherit font-lock-keyword-face)))
   "Face for highlighting parenthesized lists of functions or variables."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-list-face 'face-alias 'change-log-list)
+(define-obsolete-face-alias 'change-log-list-face 'change-log-list "22.1")
 
 (defface change-log-conditionals
   '((t (:inherit font-lock-variable-name-face)))
   "Face for highlighting conditionals of the form `[...]'."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-conditionals-face 'face-alias 'change-log-conditionals)
+(define-obsolete-face-alias 'change-log-conditionals-face
+  'change-log-conditionals "22.1")
 
 (defface change-log-function
   '((t (:inherit font-lock-variable-name-face)))
   "Face for highlighting items of the form `<....>'."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-function-face 'face-alias 'change-log-function)
+(define-obsolete-face-alias 'change-log-function-face
+  'change-log-function "22.1")
 
 (defface change-log-acknowledgement
   '((t (:inherit font-lock-comment-face)))
   "Face for highlighting acknowledgments."
   :version "21.1"
   :group 'change-log)
-;; backward-compatibility alias
-(put 'change-log-acknowledgement-face 'face-alias 'change-log-acknowledgement)
+(define-obsolete-face-alias 'change-log-acknowledgement-face
+  'change-log-acknowledgement "22.1")
 
 (defconst change-log-file-names-re "^\\( +\\|\t\\)\\* \\([^ ,:([\n]+\\)")
 (defconst change-log-start-entry-re "^\\sw.........[0-9:+ ]*")
@@ -305,7 +301,7 @@ Note: The search is conducted only within 10%, at the beginning of the file."
          (match-string-no-properties 2)
        ;; Look backwards for either a file name or the log entry start.
        (if (re-search-backward
-            (concat "\\(" change-log-start-entry-re 
+            (concat "\\(" change-log-start-entry-re
                     "\\)\\|\\("
                     change-log-file-names-re "\\)") nil t)
            (if (match-beginning 1)
@@ -351,8 +347,8 @@ the tag was found."
 
 (defun change-log-search-tag-name (&optional at)
   "Search for a tag name near `point'.
-Optional argument AT non-nil means search near buffer position
-AT.  Return value is a cons whose car is the string representing
+Optional argument AT non-nil means search near buffer position AT.
+Return value is a cons whose car is the string representing
 the tag and whose cdr is the position where the tag was found."
   (save-excursion
     (goto-char (setq at (or at (point))))
@@ -414,6 +410,7 @@ the tag and whose cdr is the position where the tag was found."
 
 (defvar change-log-find-head nil)
 (defvar change-log-find-tail nil)
+(defvar change-log-find-window nil)
 
 (defun change-log-goto-source-1 (tag regexp file buffer
                                     &optional window first last)
@@ -456,7 +453,8 @@ BUFFER denoting the last match for TAG in the last search."
                ;; Record this as first match when there's none.
                (unless first (setq first last)))))))
     (if (or last first)
-       (with-selected-window (or window (display-buffer buffer))
+       (with-selected-window
+           (setq change-log-find-window (or window (display-buffer buffer)))
          (if last
              (progn
                (when (or (< last (point-min)) (> last (point-max)))
@@ -511,7 +509,8 @@ try to visit the file for the change under `point' instead."
          ;; We either have not found a suitable file name or `file-2'
          ;; provides a "better" file name wrt `point'.  Go to the
          ;; buffer of `file-2' instead.
-         (display-buffer (find-file-noselect file-2)))
+         (setq change-log-find-window
+               (display-buffer (find-file-noselect file-2))))
         (t
          (setq change-log-find-head
                (list tag (concat "\\_<" (regexp-quote tag) "\\_>")
@@ -524,7 +523,7 @@ try to visit the file for the change under `point' instead."
                     tag file)))))))))
 
 (defun change-log-next-error (&optional argp reset)
-  "Move to the Nth (default 1) next match in an Occur mode buffer.
+  "Move to the Nth (default 1) next match in a ChangeLog buffer.
 Compatibility function for \\[next-error] invocations."
   (interactive "p")
   (let* ((argp (or argp 0))
@@ -544,17 +543,33 @@ Compatibility function for \\[next-error] invocations."
   (beginning-of-line)
   ;; if we found a place to visit...
   (when (looking-at change-log-file-names-re)
-    (change-log-goto-source)
-    ;; go to the file itself
-    (let ((file (nth 2 change-log-find-head)))
-      (when file (pop-to-buffer (find-file-noselect file))))))
+    (let (change-log-find-window)
+      (change-log-goto-source)
+      (when change-log-find-window
+       ;; Select window displaying source file.
+       (select-window change-log-find-window)))))
 
 (defvar change-log-mode-map
-  (let ((map (make-sparse-keymap)))
+  (let ((map (make-sparse-keymap))
+       (menu-map (make-sparse-keymap)))
     (define-key map [?\C-c ?\C-p] 'add-log-edit-prev-comment)
     (define-key map [?\C-c ?\C-n] 'add-log-edit-next-comment)
     (define-key map [?\C-c ?\C-f] 'change-log-find-file)
     (define-key map [?\C-c ?\C-c] 'change-log-goto-source)
+    (define-key map [menu-bar changelog] (cons "ChangeLog" menu-map))
+    (define-key menu-map [gs]
+      '(menu-item "Go To Source" change-log-goto-source
+                 :help "Go to source location of ChangeLog tag near point"))
+    (define-key menu-map [ff]
+      '(menu-item "Find File" change-log-find-file
+                 :help "Visit the file for the change under point"))
+    (define-key menu-map [sep] '("--"))
+    (define-key menu-map [nx]
+      '(menu-item "Next Log-Edit Comment" add-log-edit-next-comment
+                 :help "Cycle forward through Log-Edit mode comment history"))
+    (define-key menu-map [pr]
+      '(menu-item "Previous Log-Edit Comment" add-log-edit-prev-comment
+                 :help "Cycle backward through Log-Edit mode comment history"))
     map)
   "Keymap for Change Log major mode.")
 
@@ -666,7 +681,7 @@ nil, by matching `change-log-version-number-regexp-list'."
            version)))))
 
 (declare-function diff-find-source-location "diff-mode"
-                 (&optional other-file reverse))
+                 (&optional other-file reverse noprompt))
 
 ;;;###autoload
 (defun find-change-log (&optional file-name buffer-file)
@@ -686,51 +701,52 @@ current buffer to the complete file name.
 Optional arg BUFFER-FILE overrides `buffer-file-name'."
   ;; If we are called from a diff, first switch to the source buffer;
   ;; in order to respect buffer-local settings of change-log-default-name, etc.
-  (let ((buff (if (eq major-mode 'diff-mode)
-                 (car (ignore-errors (diff-find-source-location))))))
-    (with-current-buffer (if (buffer-live-p buff) buff
-                          (current-buffer))
+  (with-current-buffer (let ((buff (if (eq major-mode 'diff-mode)
+                                      (car (ignore-errors
+                                            (diff-find-source-location))))))
+                        (if (buffer-live-p buff) buff
+                          (current-buffer)))
       ;; If user specified a file name or if this buffer knows which one to use,
       ;; just use that.
-      (or file-name
-         (setq file-name (and change-log-default-name
-                              (file-name-directory change-log-default-name)
-                              change-log-default-name)))
-      (progn
-       ;; Chase links in the source file
-       ;; and use the change log in the dir where it points.
-       (setq file-name (or (and (or buffer-file buffer-file-name)
-                                (file-name-directory
-                                 (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)))
-       ;; Chase links before visiting the file.
-       ;; This makes it easier to use a single change log file
-       ;; for several related directories.
-       (setq file-name (file-chase-links file-name))
-       (setq file-name (expand-file-name file-name))
-       ;; Move up in the dir hierarchy till we find a change log file.
-       (let ((file1 file-name)
-             parent-dir)
-         (while (and (not (or (get-file-buffer file1) (file-exists-p file1)))
-                     (progn (setq parent-dir
+    (or file-name
+       (setq file-name (and change-log-default-name
+                            (file-name-directory change-log-default-name)
+                            change-log-default-name))
+       (progn
+         ;; Chase links in the source file
+         ;; and use the change log in the dir where it points.
+         (setq file-name (or (and (or buffer-file buffer-file-name)
                                   (file-name-directory
-                                   (directory-file-name
-                                    (file-name-directory file1))))
-                            ;; Give up if we are already at the root dir.
-                            (not (string= (file-name-directory file1)
-                                          parent-dir))))
-           ;; Move up to the parent dir and try again.
-           (setq file1 (expand-file-name
-                        (file-name-nondirectory (change-log-name))
-                        parent-dir)))
-         ;; If we found a change log in a parent, use that.
-         (if (or (get-file-buffer file1) (file-exists-p file1))
-             (setq file-name file1))))
-      ;; Make a local variable in this buffer so we needn't search again.
-      (set (make-local-variable 'change-log-default-name) 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)))
+         ;; Chase links before visiting the file.
+         ;; This makes it easier to use a single change log file
+         ;; for several related directories.
+         (setq file-name (file-chase-links file-name))
+         (setq file-name (expand-file-name file-name))
+         ;; Move up in the dir hierarchy till we find a change log file.
+         (let ((file1 file-name)
+               parent-dir)
+           (while (and (not (or (get-file-buffer file1) (file-exists-p file1)))
+                       (progn (setq parent-dir
+                                    (file-name-directory
+                                     (directory-file-name
+                                      (file-name-directory file1))))
+                              ;; Give up if we are already at the root dir.
+                              (not (string= (file-name-directory file1)
+                                            parent-dir))))
+             ;; Move up to the parent dir and try again.
+             (setq file1 (expand-file-name
+                          (file-name-nondirectory (change-log-name))
+                          parent-dir)))
+           ;; If we found a change log in a parent, use that.
+           (if (or (get-file-buffer file1) (file-exists-p file1))
+               (setq file-name file1)))))
+    ;; Make a local variable in this buffer so we needn't search again.
+    (set (make-local-variable 'change-log-default-name) file-name))
   file-name)
 
 (defun add-log-file-name (buffer-file log-file)
@@ -791,9 +807,15 @@ non-nil, otherwise in local time."
         (item (add-log-file-name buffer-file file-name)))
 
     (unless (equal file-name buffer-file-name)
-      (if (or other-window (window-dedicated-p (selected-window)))
-         (find-file-other-window file-name)
-       (find-file file-name)))
+      (cond
+       ((equal file-name (buffer-file-name (window-buffer (selected-window))))
+        ;; If the selected window already shows the desired buffer don't show
+        ;; it again (particularly important if other-window is true).
+        ;; This is important for diff-add-change-log-entries-other-window.
+        (set-buffer (window-buffer (selected-window))))
+       ((or other-window (window-dedicated-p (selected-window)))
+        (find-file-other-window file-name))
+       (t (find-file file-name))))
     (or (derived-mode-p 'change-log-mode)
        (change-log-mode))
     (undo-boundary)
@@ -1002,19 +1024,21 @@ the change log file in another window."
 
 ;;;###autoload
 (define-derived-mode change-log-mode text-mode "Change Log"
-  "Major mode for editing change logs; like Indented Text Mode.
+  "Major mode for editing change logs; like Indented Text mode.
 Prevents numeric backups and sets `left-margin' to 8 and `fill-column' to 74.
 New log entries are usually made with \\[add-change-log-entry] or \\[add-change-log-entry-other-window].
 Each entry behaves as a paragraph, and the entries for one day as a page.
 Runs `change-log-mode-hook'.
-\\{change-log-mode-map}"
+\n\\{change-log-mode-map}"
   (setq left-margin 8
        fill-column 74
        indent-tabs-mode t
        tab-width 8
        show-trailing-whitespace t)
-  (set (make-local-variable 'fill-paragraph-function)
-       'change-log-fill-paragraph)
+  (set (make-local-variable 'fill-forward-paragraph-function)
+       'change-log-fill-forward-paragraph)
+  ;; Make sure we call `change-log-indent' when filling.
+  (set (make-local-variable 'fill-indent-according-to-mode) t)
   ;; Avoid that filling leaves behind a single "*" on a line.
   (add-hook 'fill-nobreak-predicate
            '(lambda ()
@@ -1040,9 +1064,9 @@ Runs `change-log-mode-hook'.
        '(change-log-font-lock-keywords t nil nil backward-paragraph))
   (set (make-local-variable 'multi-isearch-next-buffer-function)
        'change-log-next-buffer)
-  (set (make-local-variable 'beginning-of-defun-function) 
+  (set (make-local-variable 'beginning-of-defun-function)
        'change-log-beginning-of-defun)
-  (set (make-local-variable 'end-of-defun-function) 
+  (set (make-local-variable 'end-of-defun-function)
        'change-log-end-of-defun)
   ;; next-error function glue
   (setq next-error-function 'change-log-next-error)
@@ -1070,27 +1094,18 @@ file were isearch was started."
        (cadr (member (file-name-nondirectory (buffer-file-name buffer))
                     files))))))
 
-;; It might be nice to have a general feature to replace this.  The idea I
-;; have is a variable giving a regexp matching text which should not be
-;; moved from bol by filling.  change-log-mode would set this to "^\\s *\\s(".
-;; But I don't feel up to implementing that today.
-(defun change-log-fill-paragraph (&optional justify)
-  "Fill the paragraph, but preserve open parentheses at beginning of lines.
-Prefix arg means justify as well."
-  (interactive "P")
-  (let ((end (progn (forward-paragraph) (point)))
-       (beg (progn (backward-paragraph) (point)))
-       ;; Add lines starting with whitespace followed by a left paren or an
+(defun change-log-fill-forward-paragraph (n)
+  "Cut paragraphs so filling preserves open parentheses at beginning of lines."
+  (let (;; Add lines starting with whitespace followed by a left paren or an
        ;; asterisk.
-       (paragraph-start (concat paragraph-start "\\|\\s *\\(?:\\s(\\|\\*\\)"))
-       ;; Make sure we call `change-log-indent'.
-       (fill-indent-according-to-mode t))
-    (fill-region beg end justify)
-    t))
+       (paragraph-start (concat paragraph-start "\\|\\s *\\(?:\\s(\\|\\*\\)")))
+    (forward-paragraph n)))
 \f
 (defcustom add-log-current-defun-header-regexp
   "^\\([[:upper:]][[:upper:]_ ]*[[:upper:]_]\\|[-_[:alpha:]]+\\)[ \t]*[:=]"
-  "Heuristic regexp used by `add-log-current-defun' for unknown major modes."
+  "Heuristic regexp used by `add-log-current-defun' for unknown major modes.
+The regexp's first submatch is placed in the ChangeLog entry, in
+parentheses."
   :type 'regexp
   :group 'change-log)