Function: add-change-log-entry

add-change-log-entry is an autoloaded, interactive and byte-compiled function defined in add-log.el.gz.

Signature

(add-change-log-entry &optional WHOAMI CHANGELOG-FILE-NAME OTHER-WINDOW NEW-ENTRY PUT-NEW-ENTRY-ON-NEW-LINE)

Documentation

Find ChangeLog buffer, add an entry for today and an item for this file.

Optional arg WHOAMI (interactive prefix) non-nil means prompt for user name and email (stored in add-log-full-name and add-log-mailing-address).

Second arg CHANGELOG-FILE-NAME is the file name of the change log. If nil, use the value of change-log-default-name. If the file thus named exists, it is used for the new entry. If it doesn't exist, it is created, unless add-log-dont-create-changelog-file is t, in which case a suitably named buffer that doesn't visit any file is used for keeping entries pertaining to CHANGELOG-FILE-NAME's directory.

Third arg OTHER-WINDOW non-nil means visit in other window.

Fourth arg NEW-ENTRY non-nil means always create a new entry at the front; never append to an existing entry. Option add-log-keep-changes-together otherwise affects whether a new entry is created.

Fifth arg PUT-NEW-ENTRY-ON-NEW-LINE non-nil means that if a new entry is created, put it on a new line by itself, do not put it after a comma on an existing line.

Option add-log-always-start-new-record non-nil means always create a new record, even when the last record was made on the same date and by the same person.

The change log file can start with a copyright notice and a copying permission notice. The first blank line indicates the end of these notices.

Today's date is calculated according to add-log-time-zone-rule if non-nil, otherwise in local time.

Probably introduced at or before Emacs version 16.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/vc/add-log.el.gz
;;;###autoload
(defun add-change-log-entry (&optional whoami
                                       changelog-file-name
                                       other-window new-entry
				       put-new-entry-on-new-line)
  "Find ChangeLog buffer, add an entry for today and an item for this file.
Optional arg WHOAMI (interactive prefix) non-nil means prompt for
user name and email (stored in `add-log-full-name'
and `add-log-mailing-address').

Second arg CHANGELOG-FILE-NAME is the file name of the change log.
If nil, use the value of `change-log-default-name'.  If the file
thus named exists, it is used for the new entry.  If it doesn't
exist, it is created, unless `add-log-dont-create-changelog-file' is t,
in which case a suitably named buffer that doesn't visit any file
is used for keeping entries pertaining to CHANGELOG-FILE-NAME's
directory.

Third arg OTHER-WINDOW non-nil means visit in other window.

Fourth arg NEW-ENTRY non-nil means always create a new entry at the front;
never append to an existing entry.  Option `add-log-keep-changes-together'
otherwise affects whether a new entry is created.

Fifth arg PUT-NEW-ENTRY-ON-NEW-LINE non-nil means that if a new
entry is created, put it on a new line by itself, do not put it
after a comma on an existing line.

Option `add-log-always-start-new-record' non-nil means always create a
new record, even when the last record was made on the same date and by
the same person.

The change log file can start with a copyright notice and a copying
permission notice.  The first blank line indicates the end of these
notices.

Today's date is calculated according to `add-log-time-zone-rule' if
non-nil, otherwise in local time."
  (interactive (list current-prefix-arg
		     (prompt-for-change-log-name)))
  (let* ((defun (add-log-current-defun))
	 (version (and change-log-version-info-enabled
		       (change-log-version-number-search)))
	 (buf-file-name (funcall add-log-buffer-file-name-function))
	 (buffer-file (if buf-file-name (expand-file-name buf-file-name)))
	 (changelog-file-name (expand-file-name (find-change-log
                                                 changelog-file-name
                                                 buffer-file)))
	 ;; Set ITEM to the file name to use in the new item.
	 (item (add-log-file-name buffer-file changelog-file-name)))

    ;; don't add entries from the ChangeLog file/buffer to itself.
    (unless (equal changelog-file-name buffer-file-name)
      (cond
       ((add-log--changelog-buffer-p
         changelog-file-name
         (window-buffer))
        ;; 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)))
       ((or other-window (window-dedicated-p))
        (switch-to-buffer-other-window
         (add-log-find-changelog-buffer changelog-file-name)))
       (t
        (switch-to-buffer
         (add-log-find-changelog-buffer changelog-file-name)))))
    (or (derived-mode-p 'change-log-mode)
	(change-log-mode))
    (undo-boundary)
    (goto-char (point-min))

    (let ((full-name (or add-log-full-name (user-full-name)))
          (mailing-address (or add-log-mailing-address user-mail-address)))

      (when whoami
        (setq full-name (read-string "Full name: " full-name))
        ;; Note that some sites have room and phone number fields in
        ;; full name which look silly when inserted.  Rather than do
        ;; anything about that here, let user give prefix argument so that
        ;; s/he can edit the full name field in prompter if s/he wants.
        (setq mailing-address
	      (read-string "Mailing address: " mailing-address)))

      ;; If file starts with a copyright and permission notice, skip them.
      ;; Assume they end at first blank line.
      (when (looking-at "Copyright")
        (search-forward "\n\n")
        (skip-chars-forward "\n"))

      ;; Advance into first entry if it is usable; else make new one.
      (let ((new-entries
             (mapcar (lambda (addr)
                       (concat
                        (funcall add-log-time-format
                                 nil add-log-time-zone-rule)
                        "  " full-name
                        "  <" addr ">"))
                     (if (consp mailing-address)
                         mailing-address
                       (list mailing-address)))))
        (if (and (not add-log-always-start-new-record)
                 (let ((hit nil))
                   (dolist (entry new-entries hit)
                     (and (looking-at (regexp-quote entry))
			  ;; Reject multiple author entries.  (Bug#8645)
			  (save-excursion
			    (forward-line 1)
			    (not (looking-at "[ \t]+.*<.*>$")))
			  (setq hit t)))))
            (forward-line 1)
          (insert (and new-entries (seq-random-elt new-entries))
                  (if use-hard-newlines hard-newline "\n")
                  (if use-hard-newlines hard-newline "\n"))
          (forward-line -1))))

    ;; Determine where we should stop searching for a usable
    ;; item to add to, within this entry.
    (let ((bound
           (save-excursion
             (if (looking-at "\n*[^\n* \t]")
                 (skip-chars-forward "\n")
               (if add-log-keep-changes-together
                   (forward-page)      ; page delimits entries for date
                 (forward-paragraph))) ; paragraph delimits entries for file
             (point))))

      ;; Now insert the new line for this item.
      (cond ((re-search-forward "^\\s *\\* *$" bound t)
             ;; Put this file name into the existing empty item.
             (if item
                 (insert item)))
            ((and (not new-entry)
                  (let (case-fold-search)
                    (re-search-forward
                     (concat (regexp-quote (concat "* " item))
                             ;; Don't accept `foo.bar' when
                             ;; looking for `foo':
                             "\\(\\s \\|[(),:]\\)")
                     bound t)))
             ;; Add to the existing item for the same file.
             (if (re-search-forward "^\\s *$\\|^\\s \\*" nil t)
                 (goto-char (match-beginning 0))
               (goto-char (point-max))
               (insert "\n"))
             ;; Delete excess empty lines; make just 2.
             (while (and (not (eobp)) (looking-at "^\\s *$"))
               (delete-region (point) (line-beginning-position 2)))
             (insert (if use-hard-newlines hard-newline "\n")
                     (if use-hard-newlines hard-newline "\n"))
             (forward-line -2)
             (indent-relative-first-indent-point))
            (t
             ;; Make a new item.
             (while (looking-at "\\sW")
               (forward-line 1))
             (while (and (not (eobp)) (looking-at "^\\s *$"))
               (delete-region (point) (line-beginning-position 2)))
             (insert (if use-hard-newlines hard-newline "\n")
                     (if use-hard-newlines hard-newline "\n")
                     (if use-hard-newlines hard-newline "\n"))
             (forward-line -2)
             (indent-to left-margin)
             (insert "* ")
             (if item (insert item)))))
    ;; 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 (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 *\\(\\* *\\)?$"))
	  (insert ": ")
	  (if version (insert version ?\s)))
      ;; Make it easy to get rid of the function name.
      (undo-boundary)
      (unless (save-excursion
		(beginning-of-line 1)
		(looking-at "\\s *$"))
	(insert ?\s))
      ;; 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 (not put-new-entry-on-new-line)
		 (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 ", ")))
	  (when (and (not put-new-entry-on-new-line) (looking-at "):"))
	    (delete-region (+ 1 (point)) (line-end-position)))
	  (goto-char pos)
	  (insert "("))
	(set-marker pos nil))
      (insert defun "): ")
      (if version (insert version ?\s)))))