]> code.delx.au - gnu-emacs/blobdiff - lisp/add-log.el
*** empty log message ***
[gnu-emacs] / lisp / add-log.el
index 1c3f70a9b7714cd3f873a549dae69c4ba9f1eacd..32eb5e8e403bb34948f6bcab4a226c888a061178 100644 (file)
@@ -1,6 +1,7 @@
 ;;; add-log.el --- change log maintenance commands for Emacs
 
-;; Copyright (C) 1985, 86, 88, 93, 94, 97, 98, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 86, 88, 93, 94, 97, 98, 2000, 2003
+;;           Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: tools
@@ -50,6 +51,8 @@
   :type 'hook
   :group 'change-log)
 
+;; Many modes set this variable, so avoid warnings.
+;;;###autoload
 (defcustom add-log-current-defun-function nil
   "*If non-nil, function to guess name of surrounding function.
 It is used by `add-log-current-defun' in preference to built-in rules.
@@ -246,7 +249,11 @@ Note: The search is conducted only within 10%, at the beginning of the file."
      2 'change-log-acknowledgement-face))
   "Additional expressions to highlight in Change Log mode.")
 
-(defvar change-log-mode-map (make-sparse-keymap)
+(defvar change-log-mode-map
+  (let ((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)
+    map)
   "Keymap for Change Log major mode.")
 
 (defvar change-log-time-zone-rule nil
@@ -287,6 +294,31 @@ If nil, use local time.")
          "$CHANGE_LOG$.TXT"
        "ChangeLog")))
 
+(defun add-log-edit-prev-comment (arg)
+  "Cycle backward through Log-Edit mode comment history.
+With a numeric prefix ARG, go back ARG comments."
+  (interactive "*p")
+  (save-restriction
+    (narrow-to-region (point)
+                     (if (memq last-command '(add-log-edit-prev-comment
+                                              add-log-edit-next-comment))
+                         (mark) (point)))
+    (when (fboundp 'log-edit-previous-comment)
+      (log-edit-previous-comment arg)
+      (indent-region (point-min) (point-max))
+      (goto-char (point-min))
+      (unless (save-restriction (widen) (bolp))
+       (delete-region (point) (progn (skip-chars-forward " \t\n") (point))))
+      (set-mark (point-min))
+      (goto-char (point-max))
+      (delete-region (point) (progn (skip-chars-backward " \t\n") (point))))))
+
+(defun add-log-edit-next-comment (arg)
+  "Cycle forward through Log-Edit mode comment history.
+With a numeric prefix ARG, go back ARG comments."
+  (interactive "*p")
+  (add-log-edit-prev-comment (- arg)))
+
 ;;;###autoload
 (defun prompt-for-change-log-name ()
   "Prompt for a change log name."
@@ -310,27 +342,26 @@ If nil, use local time.")
 This is the value returned by `vc-workfile-version' or, if that is
 nil, by matching `change-log-version-number-regexp-list'."
   (let* ((size (buffer-size))
-        (end
+        (limit
          ;; The version number can be anywhere in the file, but
          ;; restrict search to the file beginning: 10% should be
          ;; enough to prevent some mishits.
          ;;
          ;; Apply percentage only if buffer size is bigger than
          ;; approx 100 lines.
-         (if (> size (* 100 80))
-             (/ size 10)
-           size))
-        version)
+         (if (> size (* 100 80)) (+ (point) (/ size 10)))))
     (or (and buffer-file-name (vc-workfile-version buffer-file-name))
        (save-restriction
          (widen)
-         (let ((regexps change-log-version-number-regexp-list))
+         (let ((regexps change-log-version-number-regexp-list)
+               version)
            (while regexps
              (save-excursion
                (goto-char (point-min))
-               (when (re-search-forward (pop regexps) end t)
+               (when (re-search-forward (pop regexps) limit t)
                  (setq version (match-string 1)
-                       regexps nil)))))))))
+                       regexps nil))))
+           version)))))
 
 
 ;;;###autoload
@@ -464,10 +495,10 @@ non-nil, otherwise in local time."
         (item (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))
+    (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)))
     (or (eq major-mode 'change-log-mode)
        (change-log-mode))
     (undo-boundary)
@@ -545,36 +576,39 @@ non-nil, otherwise in local time."
     ;; Now insert the function name, if we have one.
     ;; Point is at the item for this file,
     ;; either at the end of the line or at the first blank line.
-    (if defun
-       (progn
-         ;; Make it easy to get rid of the function name.
-         (undo-boundary)
-         (unless (save-excursion
-                   (beginning-of-line 1)
-                   (looking-at "\\s *$"))
-           (insert ?\ ))
-         ;; See if the prev function name has a message yet or not.
-         ;; If not, merge the two items.
-         (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.
+    (if (not defun)
+       ;; No function name, so put in a colon unless we have just a star.
+       (unless (save-excursion
+                 (beginning-of-line 1)
+                 (looking-at "\\s *\\(\\*\\s *\\)?$"))
+         (insert ": ")
+         (if version (insert version ?\ )))
+      ;; Make it easy to get rid of the function name.
+      (undo-boundary)
       (unless (save-excursion
                (beginning-of-line 1)
-               (looking-at "\\s *\\(\\*\\s *\\)?$"))
-       (insert ": ")
-       (if version (insert version ?\ ))))))
+               (looking-at "\\s *$"))
+       (insert ?\ ))
+      ;; See if the prev function name has a message yet or not.
+      ;; If not, merge the two items.
+      (let ((pos (point-marker)))
+       (skip-syntax-backward " ")
+       (skip-chars-backward "):")
+       (if (and (looking-at "):")
+                (let ((pos (save-excursion (backward-sexp 1) (point))))
+                  (when (equal (buffer-substring pos (point)) defun)
+                    (delete-region pos (point)))
+                  (> fill-column (+ (current-column) (length defun) 4))))
+           (progn (skip-chars-backward ", ")
+                  (delete-region (point) pos)
+                  (unless (memq (char-before) '(?\()) (insert ", ")))
+         (if (looking-at "):")
+             (delete-region (+ 1 (point)) (line-end-position)))
+         (goto-char pos)
+         (insert "("))
+       (set-marker pos nil))
+      (insert defun "): ")
+      (if version (insert version ?\ )))))
 
 ;;;###autoload
 (defun add-change-log-entry-other-window (&optional whoami file-name)
@@ -587,25 +621,44 @@ the change log file in another window."
   (add-change-log-entry whoami file-name t))
 ;;;###autoload (define-key ctl-x-4-map "a" 'add-change-log-entry-other-window)
 
+(defvar add-log-indent-text 0)
+
+(defun add-log-indent ()
+  (let* ((indent
+         (save-excursion
+           (beginning-of-line)
+           (skip-chars-forward " \t")
+           (cond
+            ((and (looking-at "\\(.*\\)  [^ \n].*[^ \n]  <.*>$")
+                  ;; Matching the output of add-log-time-format is difficult,
+                  ;; but I'll get it has at least two adjacent digits.
+                  (string-match "[[:digit:]][[:digit:]]" (match-string 1)))
+             0)
+            ((looking-at "[^*(]")
+             (+ (current-left-margin) add-log-indent-text))
+            (t (current-left-margin)))))
+        (pos (save-excursion (indent-line-to indent) (point))))
+    (if (> pos (point)) (goto-char pos))))
+
+
+(defvar smerge-resolve-function)
+
 ;;;###autoload
-(defun change-log-mode ()
+(define-derived-mode change-log-mode text-mode "Change Log"
   "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'."
-  (interactive)
-  (kill-all-local-variables)
-  (indented-text-mode)
-  (setq major-mode 'change-log-mode
-       mode-name "Change Log"
-       left-margin 8
+Runs `change-log-mode-hook'.
+\\{change-log-mode-map}"
+  (setq left-margin 8
        fill-column 74
        indent-tabs-mode t
        tab-width 8)
-  (use-local-map change-log-mode-map)
   (set (make-local-variable 'fill-paragraph-function)
        'change-log-fill-paragraph)
+  (set (make-local-variable 'indent-line-function) 'add-log-indent)
+  (set (make-local-variable 'tab-always-indent) nil)
   ;; We really do want "^" in paragraph-start below: it is only the
   ;; lines that begin at column 0 (despite the left-margin of 8) that
   ;; we are looking for.  Adding `* ' allows eliding the blank line
@@ -616,10 +669,11 @@ Runs `change-log-mode-hook'."
   ;; is grouped with what follows.
   (set (make-local-variable 'page-delimiter) "^\\<\\|^\f")
   (set (make-local-variable 'version-control) 'never)
+  (set (make-local-variable 'smerge-resolve-function)
+       'change-log-resolve-conflict)
   (set (make-local-variable 'adaptive-fill-regexp) "\\s *")
   (set (make-local-variable 'font-lock-defaults)
-       '(change-log-font-lock-keywords t nil nil backward-paragraph))
-  (run-hooks 'change-log-mode-hook))
+       '(change-log-font-lock-keywords t nil nil backward-paragraph)))
 
 ;; 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
@@ -833,7 +887,7 @@ Has a preference of looking backwards."
                 (if (re-search-backward "^@node[ \t]+\\([^,\n]+\\)" nil t)
                     (match-string-no-properties 1)))
                ((memq major-mode '(perl-mode cperl-mode))
-                (if (re-search-backward "^sub[ \t]+\\([^ \t\n]+\\)" nil t)
+                (if (re-search-backward "^sub[ \t]+\\([^({ \t\n]+\\)" nil t)
                     (match-string-no-properties 1)))
                ;; Emacs's autoconf-mode installs its own
                ;; `add-log-current-defun-function'.  This applies to
@@ -904,18 +958,34 @@ Point is assumed to be at the start of the entry."
                (error nil)))))
     (error "Bad date")))
 
+(defun change-log-resolve-conflict ()
+  "Function to be used in `smerge-resolve-function'."
+  (let ((buf (current-buffer)))
+    (with-temp-buffer
+      (insert-buffer-substring buf (match-beginning 1) (match-end 1))
+      (save-match-data (change-log-mode))
+      (let ((other-buf (current-buffer)))
+       (with-current-buffer buf
+         (save-excursion
+           (save-restriction
+             (narrow-to-region (match-beginning 0) (match-end 0))
+             (replace-match (match-string 3) t t)
+             (change-log-merge other-buf))))))))
+
 ;;;###autoload
 (defun change-log-merge (other-log)
   "Merge the contents of ChangeLog file OTHER-LOG with this buffer.
 Both must be found in Change Log mode (since the merging depends on
-the appropriate motion commands).
+the appropriate motion commands).  OTHER-LOG can be either a file name
+or a buffer.
 
 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"))
-  (let ((other-buf (find-file-noselect other-log))
+  (let ((other-buf (if (bufferp other-log) other-log
+                    (find-file-noselect other-log)))
        (buf (current-buffer))
        date1 start end)
     (save-excursion
@@ -938,12 +1008,16 @@ old-style time formats for entries are supported."
              (insert-buffer-substring other-buf start end)
            ;; At the end of the original buffer, insert a newline to
            ;; separate entries and then the rest of the file being
-           ;; merged.  Move to the end of it to terminate outer loop.
-           (insert "\n")
-           (insert-buffer-substring other-buf start
-                                    (with-current-buffer other-buf
-                                      (goto-char (point-max))
-                                      (point)))))))))
+           ;; merged.
+           (unless (or (bobp)
+                       (and (= ?\n (char-before))
+                            (or (<= (1- (point)) (point-min))
+                                (= ?\n (char-before (1- (point)))))))
+             (insert "\n"))
+           ;; Move to the end of it to terminate outer loop.
+           (with-current-buffer other-buf
+             (goto-char (point-max)))
+           (insert-buffer-substring other-buf start)))))))
 
 ;;;###autoload
 (defun change-log-redate ()