comparison lisp/add-log.el @ 88155:d7ddb3e565de

sync with trunk
author Henrik Enberg <henrik.enberg@telia.com>
date Mon, 16 Jan 2006 00:03:54 +0000
parents 0e6cefe9e2d0
children
comparison
equal deleted inserted replaced
88154:8ce476d3ba36 88155:d7ddb3e565de
1 ;;; add-log.el --- change log maintenance commands for Emacs 1 ;;; add-log.el --- change log maintenance commands for Emacs
2 2
3 ;; Copyright (C) 1985, 86, 88, 93, 94, 97, 98, 2000 Free Software Foundation, Inc. 3 ;; Copyright (C) 1985, 1986, 1988, 1993, 1994, 1997, 1998, 2000, 2002,
4 ;; 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
4 5
5 ;; Maintainer: FSF 6 ;; Maintainer: FSF
6 ;; Keywords: tools 7 ;; Keywords: tools
7 8
8 ;; This file is part of GNU Emacs. 9 ;; This file is part of GNU Emacs.
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details. 19 ;; GNU General Public License for more details.
19 20
20 ;; You should have received a copy of the GNU General Public License 21 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the 22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02111-1307, USA. 24 ;; Boston, MA 02110-1301, USA.
24 25
25 ;;; Commentary: 26 ;;; Commentary:
26 27
27 ;; This facility is documented in the Emacs Manual. 28 ;; This facility is documented in the Emacs Manual.
28 29
30 31
31 (eval-when-compile 32 (eval-when-compile
32 (require 'timezone)) 33 (require 'timezone))
33 34
34 (defgroup change-log nil 35 (defgroup change-log nil
35 "Change log maintenance" 36 "Change log maintenance."
36 :group 'tools 37 :group 'tools
37 :link '(custom-manual "(emacs)Change Log") 38 :link '(custom-manual "(emacs)Change Log")
38 :prefix "change-log-" 39 :prefix "change-log-"
39 :prefix "add-log-") 40 :prefix "add-log-")
40 41
48 (defcustom change-log-mode-hook nil 49 (defcustom change-log-mode-hook nil
49 "Normal hook run by `change-log-mode'." 50 "Normal hook run by `change-log-mode'."
50 :type 'hook 51 :type 'hook
51 :group 'change-log) 52 :group 'change-log)
52 53
54 ;; Many modes set this variable, so avoid warnings.
55 ;;;###autoload
53 (defcustom add-log-current-defun-function nil 56 (defcustom add-log-current-defun-function nil
54 "*If non-nil, function to guess name of surrounding function. 57 "*If non-nil, function to guess name of surrounding function.
55 It is used by `add-log-current-defun' in preference to built-in rules. 58 It is used by `add-log-current-defun' in preference to built-in rules.
56 Returns function's name as a string, or nil if outside a function." 59 Returns function's name as a string, or nil if outside a function."
57 :type '(choice (const nil) function) 60 :type '(choice (const nil) function)
65 string) 68 string)
66 :group 'change-log) 69 :group 'change-log)
67 70
68 ;;;###autoload 71 ;;;###autoload
69 (defcustom add-log-mailing-address nil 72 (defcustom add-log-mailing-address nil
70 "*Electronic mail addresses of user, for inclusion in ChangeLog headers. 73 "*Email addresses of user, for inclusion in ChangeLog headers.
71 This defaults to the value of `user-mail-address'. In addition to 74 This defaults to the value of `user-mail-address'. In addition to
72 being a simple string, this value can also be a list. All elements 75 being a simple string, this value can also be a list. All elements
73 will be recognized as referring to the same user; when creating a new 76 will be recognized as referring to the same user; when creating a new
74 ChangeLog entry, one element will be chosen at random." 77 ChangeLog entry, one element will be chosen at random."
75 :type '(choice (const :tag "Default" nil) 78 :type '(choice (const :tag "Default" nil)
121 :type 'boolean 124 :type 'boolean
122 :group 'change-log) 125 :group 'change-log)
123 126
124 (defcustom add-log-always-start-new-record nil 127 (defcustom add-log-always-start-new-record nil
125 "*If non-nil, `add-change-log-entry' will always start a new record." 128 "*If non-nil, `add-change-log-entry' will always start a new record."
126 :version "21.4" 129 :version "22.1"
127 :type 'boolean 130 :type 'boolean
128 :group 'change-log) 131 :group 'change-log)
129 132
130 (defcustom add-log-buffer-file-name-function nil 133 (defcustom add-log-buffer-file-name-function nil
131 "*If non-nil, function to call to identify the full filename of a buffer. 134 "*If non-nil, function to call to identify the full filename of a buffer.
161 Note: The search is conducted only within 10%, at the beginning of the file." 164 Note: The search is conducted only within 10%, at the beginning of the file."
162 :version "21.1" 165 :version "21.1"
163 :type '(repeat regexp) 166 :type '(repeat regexp)
164 :group 'change-log) 167 :group 'change-log)
165 168
166 (defface change-log-date-face 169 (defface change-log-date
167 '((t (:inherit font-lock-string-face))) 170 '((t (:inherit font-lock-string-face)))
168 "Face used to highlight dates in date lines." 171 "Face used to highlight dates in date lines."
169 :version "21.1" 172 :version "21.1"
170 :group 'change-log) 173 :group 'change-log)
171 174 ;; backward-compatibility alias
172 (defface change-log-name-face 175 (put 'change-log-date-face 'face-alias 'change-log-date)
176
177 (defface change-log-name
173 '((t (:inherit font-lock-constant-face))) 178 '((t (:inherit font-lock-constant-face)))
174 "Face for highlighting author names." 179 "Face for highlighting author names."
175 :version "21.1" 180 :version "21.1"
176 :group 'change-log) 181 :group 'change-log)
177 182 ;; backward-compatibility alias
178 (defface change-log-email-face 183 (put 'change-log-name-face 'face-alias 'change-log-name)
184
185 (defface change-log-email
179 '((t (:inherit font-lock-variable-name-face))) 186 '((t (:inherit font-lock-variable-name-face)))
180 "Face for highlighting author email addresses." 187 "Face for highlighting author email addresses."
181 :version "21.1" 188 :version "21.1"
182 :group 'change-log) 189 :group 'change-log)
183 190 ;; backward-compatibility alias
184 (defface change-log-file-face 191 (put 'change-log-email-face 'face-alias 'change-log-email)
192
193 (defface change-log-file
185 '((t (:inherit font-lock-function-name-face))) 194 '((t (:inherit font-lock-function-name-face)))
186 "Face for highlighting file names." 195 "Face for highlighting file names."
187 :version "21.1" 196 :version "21.1"
188 :group 'change-log) 197 :group 'change-log)
189 198 ;; backward-compatibility alias
190 (defface change-log-list-face 199 (put 'change-log-file-face 'face-alias 'change-log-file)
200
201 (defface change-log-list
191 '((t (:inherit font-lock-keyword-face))) 202 '((t (:inherit font-lock-keyword-face)))
192 "Face for highlighting parenthesized lists of functions or variables." 203 "Face for highlighting parenthesized lists of functions or variables."
193 :version "21.1" 204 :version "21.1"
194 :group 'change-log) 205 :group 'change-log)
195 206 ;; backward-compatibility alias
196 (defface change-log-conditionals-face 207 (put 'change-log-list-face 'face-alias 'change-log-list)
208
209 (defface change-log-conditionals
197 '((t (:inherit font-lock-variable-name-face))) 210 '((t (:inherit font-lock-variable-name-face)))
198 "Face for highlighting conditionals of the form `[...]'." 211 "Face for highlighting conditionals of the form `[...]'."
199 :version "21.1" 212 :version "21.1"
200 :group 'change-log) 213 :group 'change-log)
201 214 ;; backward-compatibility alias
202 (defface change-log-function-face 215 (put 'change-log-conditionals-face 'face-alias 'change-log-conditionals)
216
217 (defface change-log-function
203 '((t (:inherit font-lock-variable-name-face))) 218 '((t (:inherit font-lock-variable-name-face)))
204 "Face for highlighting items of the form `<....>'." 219 "Face for highlighting items of the form `<....>'."
205 :version "21.1" 220 :version "21.1"
206 :group 'change-log) 221 :group 'change-log)
207 222 ;; backward-compatibility alias
208 (defface change-log-acknowledgement-face 223 (put 'change-log-function-face 'face-alias 'change-log-function)
224
225 (defface change-log-acknowledgement
209 '((t (:inherit font-lock-comment-face))) 226 '((t (:inherit font-lock-comment-face)))
210 "Face for highlighting acknowledgments." 227 "Face for highlighting acknowledgments."
211 :version "21.1" 228 :version "21.1"
212 :group 'change-log) 229 :group 'change-log)
230 ;; backward-compatibility alias
231 (put 'change-log-acknowledgement-face 'face-alias 'change-log-acknowledgement)
213 232
214 (defvar change-log-font-lock-keywords 233 (defvar change-log-font-lock-keywords
215 '(;; 234 '(;;
216 ;; Date lines, new and old styles. 235 ;; Date lines, new (2000-01-01) and old (Sat Jan 1 00:00:00 2000) styles.
217 ("^\\sw.........[0-9:+ ]*" 236 ;; Fixme: this regepx is just an approximate one and may match
237 ;; wrongly with a non-date line existing as a random note. In
238 ;; addition, using any kind of fixed setting like this doesn't
239 ;; work if a user customizes add-log-time-format.
240 ("^[0-9-]+ +\\|^\\(Sun\\|Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\) [A-z][a-z][a-z] [0-9:+ ]+"
218 (0 'change-log-date-face) 241 (0 'change-log-date-face)
219 ;; Name and e-mail; some people put e-mail in parens, not angles. 242 ;; Name and e-mail; some people put e-mail in parens, not angles.
220 ("\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+\\)[>)]" nil nil 243 ("\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]" nil nil
221 (1 'change-log-name-face) 244 (1 'change-log-name)
222 (2 'change-log-email-face))) 245 (2 'change-log-email)))
223 ;; 246 ;;
224 ;; File names. 247 ;; File names.
225 ("^\t\\* \\([^ ,:([\n]+\\)" 248 ("^\\( +\\|\t\\)\\* \\([^ ,:([\n]+\\)"
226 (1 'change-log-file-face) 249 (2 'change-log-file)
227 ;; Possibly further names in a list: 250 ;; Possibly further names in a list:
228 ("\\=, \\([^ ,:([\n]+\\)" nil nil (1 'change-log-file-face)) 251 ("\\=, \\([^ ,:([\n]+\\)" nil nil (1 'change-log-file))
229 ;; Possibly a parenthesized list of names: 252 ;; Possibly a parenthesized list of names:
230 ("\\= (\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face)) 253 ("\\= (\\([^(),\n]+\\|(\\(setf\\|SETF\\) [^() ,\n]+)\\)"
231 ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face))) 254 nil nil (1 'change-log-list))
255 ("\\=, *\\([^(),\n]+\\|(\\(setf\\|SETF\\) [^() ,\n]+)\\)"
256 nil nil (1 'change-log-list)))
232 ;; 257 ;;
233 ;; Function or variable names. 258 ;; Function or variable names.
234 ("^\t(\\([^) ,:\n]+\\)" 259 ("^\\( +\\|\t\\)(\\([^(),\n]+\\|(\\(setf\\|SETF\\) [^() ,\n]+)\\)"
235 (1 'change-log-list-face) 260 (2 'change-log-list)
236 ("\\=, *\\([^) ,:\n]+\\)" nil nil (1 'change-log-list-face))) 261 ("\\=, *\\([^(),\n]+\\|(\\(setf\\|SETF\\) [^() ,\n]+)\\)" nil nil
262 (1 'change-log-list)))
237 ;; 263 ;;
238 ;; Conditionals. 264 ;; Conditionals.
239 ("\\[!?\\([^]\n]+\\)\\]\\(:\\| (\\)" (1 'change-log-conditionals-face)) 265 ("\\[!?\\([^]\n]+\\)\\]\\(:\\| (\\)" (1 'change-log-conditionals))
240 ;; 266 ;;
241 ;; Function of change. 267 ;; Function of change.
242 ("<\\([^>\n]+\\)>\\(:\\| (\\)" (1 'change-log-function-face)) 268 ("<\\([^>\n]+\\)>\\(:\\| (\\)" (1 'change-log-function))
243 ;; 269 ;;
244 ;; Acknowledgements. 270 ;; Acknowledgements.
245 ("\\(^\t\\| \\)\\(From\\|Patch\\(es\\)? by\\|Report\\(ed by\\| from\\)\\|Suggest\\(ed by\\|ion from\\)\\)" 271 ;; Don't include plain "From" because that is vague;
246 2 'change-log-acknowledgement-face)) 272 ;; we want to encourage people to say something more specific.
273 ;; Note that the FSF does not use "Patches by"; our convention
274 ;; is to put the name of the author of the changes at the top
275 ;; of the change log entry.
276 ("\\(^\\( +\\|\t\\)\\| \\)\\(Patch\\(es\\)? by\\|Report\\(ed by\\| from\\)\\|Suggest\\(ed by\\|ion from\\)\\)"
277 3 'change-log-acknowledgement))
247 "Additional expressions to highlight in Change Log mode.") 278 "Additional expressions to highlight in Change Log mode.")
248 279
249 (defvar change-log-mode-map (make-sparse-keymap) 280 (defvar change-log-mode-map
281 (let ((map (make-sparse-keymap)))
282 (define-key map [?\C-c ?\C-p] 'add-log-edit-prev-comment)
283 (define-key map [?\C-c ?\C-n] 'add-log-edit-next-comment)
284 map)
250 "Keymap for Change Log major mode.") 285 "Keymap for Change Log major mode.")
251 286
252 (defvar change-log-time-zone-rule nil 287 (defvar change-log-time-zone-rule nil
253 "Time zone used for calculating change log time stamps. 288 "Time zone used for calculating change log time stamps.
254 It takes the same format as the TZ argument of `set-time-zone-rule'. 289 It takes the same format as the TZ argument of `set-time-zone-rule'.
284 "Return (system-dependent) default name for a change log file." 319 "Return (system-dependent) default name for a change log file."
285 (or change-log-default-name 320 (or change-log-default-name
286 (if (eq system-type 'vax-vms) 321 (if (eq system-type 'vax-vms)
287 "$CHANGE_LOG$.TXT" 322 "$CHANGE_LOG$.TXT"
288 "ChangeLog"))) 323 "ChangeLog")))
324
325 (defun add-log-edit-prev-comment (arg)
326 "Cycle backward through Log-Edit mode comment history.
327 With a numeric prefix ARG, go back ARG comments."
328 (interactive "*p")
329 (save-restriction
330 (narrow-to-region (point)
331 (if (memq last-command '(add-log-edit-prev-comment
332 add-log-edit-next-comment))
333 (mark) (point)))
334 (when (fboundp 'log-edit-previous-comment)
335 (log-edit-previous-comment arg)
336 (indent-region (point-min) (point-max))
337 (goto-char (point-min))
338 (unless (save-restriction (widen) (bolp))
339 (delete-region (point) (progn (skip-chars-forward " \t\n") (point))))
340 (set-mark (point-min))
341 (goto-char (point-max))
342 (delete-region (point) (progn (skip-chars-backward " \t\n") (point))))))
343
344 (defun add-log-edit-next-comment (arg)
345 "Cycle forward through Log-Edit mode comment history.
346 With a numeric prefix ARG, go back ARG comments."
347 (interactive "*p")
348 (add-log-edit-prev-comment (- arg)))
289 349
290 ;;;###autoload 350 ;;;###autoload
291 (defun prompt-for-change-log-name () 351 (defun prompt-for-change-log-name ()
292 "Prompt for a change log name." 352 "Prompt for a change log name."
293 (let* ((default (change-log-name)) 353 (let* ((default (change-log-name))
308 (defun change-log-version-number-search () 368 (defun change-log-version-number-search ()
309 "Return version number of current buffer's file. 369 "Return version number of current buffer's file.
310 This is the value returned by `vc-workfile-version' or, if that is 370 This is the value returned by `vc-workfile-version' or, if that is
311 nil, by matching `change-log-version-number-regexp-list'." 371 nil, by matching `change-log-version-number-regexp-list'."
312 (let* ((size (buffer-size)) 372 (let* ((size (buffer-size))
313 (end 373 (limit
314 ;; The version number can be anywhere in the file, but 374 ;; The version number can be anywhere in the file, but
315 ;; restrict search to the file beginning: 10% should be 375 ;; restrict search to the file beginning: 10% should be
316 ;; enough to prevent some mishits. 376 ;; enough to prevent some mishits.
317 ;; 377 ;;
318 ;; Apply percentage only if buffer size is bigger than 378 ;; Apply percentage only if buffer size is bigger than
319 ;; approx 100 lines. 379 ;; approx 100 lines.
320 (if (> size (* 100 80)) 380 (if (> size (* 100 80)) (+ (point) (/ size 10)))))
321 (/ size 10)
322 size))
323 version)
324 (or (and buffer-file-name (vc-workfile-version buffer-file-name)) 381 (or (and buffer-file-name (vc-workfile-version buffer-file-name))
325 (save-restriction 382 (save-restriction
326 (widen) 383 (widen)
327 (let ((regexps change-log-version-number-regexp-list)) 384 (let ((regexps change-log-version-number-regexp-list)
385 version)
328 (while regexps 386 (while regexps
329 (save-excursion 387 (save-excursion
330 (goto-char (point-min)) 388 (goto-char (point-min))
331 (when (re-search-forward (pop regexps) end t) 389 (when (re-search-forward (pop regexps) limit t)
332 (setq version (match-string 1) 390 (setq version (match-string 1)
333 regexps nil))))))))) 391 regexps nil))))
392 version)))))
334 393
335 394
336 ;;;###autoload 395 ;;;###autoload
337 (defun find-change-log (&optional file-name buffer-file) 396 (defun find-change-log (&optional file-name buffer-file)
338 "Find a change log file for \\[add-change-log-entry] and return the name. 397 "Find a change log file for \\[add-change-log-entry] and return the name.
339 398
340 Optional arg FILE-NAME specifies the file to use. 399 Optional arg FILE-NAME specifies the file to use.
341 If FILE-NAME is nil, use the value of `change-log-default-name'. 400 If FILE-NAME is nil, use the value of `change-log-default-name'.
342 If 'change-log-default-name' is nil, behave as though it were 'ChangeLog' 401 If `change-log-default-name' is nil, behave as though it were 'ChangeLog'
343 \(or whatever we use on this operating system). 402 \(or whatever we use on this operating system).
344 403
345 If 'change-log-default-name' contains a leading directory component, then 404 If `change-log-default-name' contains a leading directory component, then
346 simply find it in the current directory. Otherwise, search in the current 405 simply find it in the current directory. Otherwise, search in the current
347 directory and its successive parents for a file so named. 406 directory and its successive parents for a file so named.
348 407
349 Once a file is found, `change-log-default-name' is set locally in the 408 Once a file is found, `change-log-default-name' is set locally in the
350 current buffer to the complete file name. 409 current buffer to the complete file name.
412 471
413 ;;;###autoload 472 ;;;###autoload
414 (defun add-change-log-entry (&optional whoami file-name other-window new-entry) 473 (defun add-change-log-entry (&optional whoami file-name other-window new-entry)
415 "Find change log file, and add an entry for today and an item for this file. 474 "Find change log file, and add an entry for today and an item for this file.
416 Optional arg WHOAMI (interactive prefix) non-nil means prompt for user 475 Optional arg WHOAMI (interactive prefix) non-nil means prompt for user
417 name and site. 476 name and email (stored in `add-log-full-name' and `add-log-mailing-address').
418 477
419 Second arg FILE-NAME is file name of the change log. 478 Second arg FILE-NAME is file name of the change log.
420 If nil, use the value of `change-log-default-name'. 479 If nil, use the value of `change-log-default-name'.
421 480
422 Third arg OTHER-WINDOW non-nil means visit in other window. 481 Third arg OTHER-WINDOW non-nil means visit in other window.
435 494
436 Today's date is calculated according to `change-log-time-zone-rule' if 495 Today's date is calculated according to `change-log-time-zone-rule' if
437 non-nil, otherwise in local time." 496 non-nil, otherwise in local time."
438 (interactive (list current-prefix-arg 497 (interactive (list current-prefix-arg
439 (prompt-for-change-log-name))) 498 (prompt-for-change-log-name)))
440 (or add-log-full-name
441 (setq add-log-full-name (user-full-name)))
442 (or add-log-mailing-address
443 (setq add-log-mailing-address user-mail-address))
444 (if whoami
445 (progn
446 (setq add-log-full-name (read-input "Full name: " add-log-full-name))
447 ;; Note that some sites have room and phone number fields in
448 ;; full name which look silly when inserted. Rather than do
449 ;; anything about that here, let user give prefix argument so that
450 ;; s/he can edit the full name field in prompter if s/he wants.
451 (setq add-log-mailing-address
452 (read-input "Mailing address: " add-log-mailing-address))))
453
454 (let* ((defun (add-log-current-defun)) 499 (let* ((defun (add-log-current-defun))
455 (version (and change-log-version-info-enabled 500 (version (and change-log-version-info-enabled
456 (change-log-version-number-search))) 501 (change-log-version-number-search)))
457 (buf-file-name (if add-log-buffer-file-name-function 502 (buf-file-name (if add-log-buffer-file-name-function
458 (funcall add-log-buffer-file-name-function) 503 (funcall add-log-buffer-file-name-function)
459 buffer-file-name)) 504 buffer-file-name))
460 (buffer-file (if buf-file-name (expand-file-name buf-file-name))) 505 (buffer-file (if buf-file-name (expand-file-name buf-file-name)))
461 (file-name (expand-file-name 506 (file-name (expand-file-name (find-change-log file-name buffer-file)))
462 (or file-name (find-change-log file-name buffer-file))))
463 ;; Set ITEM to the file name to use in the new item. 507 ;; Set ITEM to the file name to use in the new item.
464 (item (add-log-file-name buffer-file file-name)) 508 (item (add-log-file-name buffer-file file-name))
465 bound) 509 bound
510 (full-name (or add-log-full-name (user-full-name)))
511 (mailing-address (or add-log-mailing-address user-mail-address)))
512
513 (if whoami
514 (progn
515 (setq full-name (read-string "Full name: " full-name))
516 ;; Note that some sites have room and phone number fields in
517 ;; full name which look silly when inserted. Rather than do
518 ;; anything about that here, let user give prefix argument so that
519 ;; s/he can edit the full name field in prompter if s/he wants.
520 (setq mailing-address
521 (read-string "Mailing address: " mailing-address))))
466 522
467 (unless (equal file-name buffer-file-name) 523 (unless (equal file-name buffer-file-name)
468 (if (or other-window (window-dedicated-p (selected-window))) 524 (if (or other-window (window-dedicated-p (selected-window)))
469 (find-file-other-window file-name) 525 (find-file-other-window file-name)
470 (find-file file-name))) 526 (find-file file-name)))
480 (skip-chars-forward "\n")) 536 (skip-chars-forward "\n"))
481 537
482 ;; Advance into first entry if it is usable; else make new one. 538 ;; Advance into first entry if it is usable; else make new one.
483 (let ((new-entries (mapcar (lambda (addr) 539 (let ((new-entries (mapcar (lambda (addr)
484 (concat (funcall add-log-time-format) 540 (concat (funcall add-log-time-format)
485 " " add-log-full-name 541 " " full-name
486 " <" addr ">")) 542 " <" addr ">"))
487 (if (consp add-log-mailing-address) 543 (if (consp mailing-address)
488 add-log-mailing-address 544 mailing-address
489 (list add-log-mailing-address))))) 545 (list mailing-address)))))
490 (if (and (not add-log-always-start-new-record) 546 (if (and (not add-log-always-start-new-record)
491 (let ((hit nil)) 547 (let ((hit nil))
492 (dolist (entry new-entries hit) 548 (dolist (entry new-entries hit)
493 (when (looking-at (regexp-quote entry)) 549 (when (looking-at (regexp-quote entry))
494 (setq hit t))))) 550 (setq hit t)))))
495 (forward-line 1) 551 (forward-line 1)
496 (insert (nth (random (length new-entries)) 552 (insert (nth (random (length new-entries))
497 new-entries) 553 new-entries)
498 "\n\n") 554 (if use-hard-newlines hard-newline "\n")
555 (if use-hard-newlines hard-newline "\n"))
499 (forward-line -1))) 556 (forward-line -1)))
500 557
501 ;; Determine where we should stop searching for a usable 558 ;; Determine where we should stop searching for a usable
502 ;; item to add to, within this entry. 559 ;; item to add to, within this entry.
503 (setq bound 560 (setq bound
526 (re-search-forward "^\\s *$\\|^\\s \\*") 583 (re-search-forward "^\\s *$\\|^\\s \\*")
527 (goto-char (match-beginning 0)) 584 (goto-char (match-beginning 0))
528 ;; Delete excess empty lines; make just 2. 585 ;; Delete excess empty lines; make just 2.
529 (while (and (not (eobp)) (looking-at "^\\s *$")) 586 (while (and (not (eobp)) (looking-at "^\\s *$"))
530 (delete-region (point) (line-beginning-position 2))) 587 (delete-region (point) (line-beginning-position 2)))
531 (insert-char ?\n 2) 588 (insert (if use-hard-newlines hard-newline "\n")
589 (if use-hard-newlines hard-newline "\n"))
532 (forward-line -2) 590 (forward-line -2)
533 (indent-relative-maybe)) 591 (indent-relative-maybe))
534 (t 592 (t
535 ;; Make a new item. 593 ;; Make a new item.
536 (while (looking-at "\\sW") 594 (while (looking-at "\\sW")
537 (forward-line 1)) 595 (forward-line 1))
538 (while (and (not (eobp)) (looking-at "^\\s *$")) 596 (while (and (not (eobp)) (looking-at "^\\s *$"))
539 (delete-region (point) (line-beginning-position 2))) 597 (delete-region (point) (line-beginning-position 2)))
540 (insert-char ?\n 3) 598 (insert (if use-hard-newlines hard-newline "\n")
599 (if use-hard-newlines hard-newline "\n")
600 (if use-hard-newlines hard-newline "\n"))
541 (forward-line -2) 601 (forward-line -2)
542 (indent-to left-margin) 602 (indent-to left-margin)
543 (insert "* ") 603 (insert "* ")
544 (if item (insert item)))) 604 (if item (insert item))))
545 ;; Now insert the function name, if we have one. 605 ;; Now insert the function name, if we have one.
549 ;; No function name, so put in a colon unless we have just a star. 609 ;; No function name, so put in a colon unless we have just a star.
550 (unless (save-excursion 610 (unless (save-excursion
551 (beginning-of-line 1) 611 (beginning-of-line 1)
552 (looking-at "\\s *\\(\\*\\s *\\)?$")) 612 (looking-at "\\s *\\(\\*\\s *\\)?$"))
553 (insert ": ") 613 (insert ": ")
554 (if version (insert version ?\ ))) 614 (if version (insert version ?\s)))
555 ;; Make it easy to get rid of the function name. 615 ;; Make it easy to get rid of the function name.
556 (undo-boundary) 616 (undo-boundary)
557 (unless (save-excursion 617 (unless (save-excursion
558 (beginning-of-line 1) 618 (beginning-of-line 1)
559 (looking-at "\\s *$")) 619 (looking-at "\\s *$"))
560 (insert ?\ )) 620 (insert ?\s))
561 ;; See if the prev function name has a message yet or not. 621 ;; See if the prev function name has a message yet or not.
562 ;; If not, merge the two items. 622 ;; If not, merge the two items.
563 (let ((pos (point-marker))) 623 (let ((pos (point-marker)))
564 (skip-syntax-backward " ") 624 (skip-syntax-backward " ")
565 (skip-chars-backward "):") 625 (skip-chars-backward "):")
566 (if (and (looking-at "):") 626 (if (and (looking-at "):")
567 (> fill-column (+ (current-column) (length defun) 4))) 627 (let ((pos (save-excursion (backward-sexp 1) (point))))
568 (progn (delete-region (point) pos) (insert ", ")) 628 (when (equal (buffer-substring pos (point)) defun)
629 (delete-region pos (point)))
630 (> fill-column (+ (current-column) (length defun) 4))))
631 (progn (skip-chars-backward ", ")
632 (delete-region (point) pos)
633 (unless (memq (char-before) '(?\()) (insert ", ")))
569 (if (looking-at "):") 634 (if (looking-at "):")
570 (delete-region (+ 1 (point)) (line-end-position))) 635 (delete-region (+ 1 (point)) (line-end-position)))
571 (goto-char pos) 636 (goto-char pos)
572 (insert "(")) 637 (insert "("))
573 (set-marker pos nil)) 638 (set-marker pos nil))
574 (insert defun "): ") 639 (insert defun "): ")
575 (if version (insert version ?\ ))))) 640 (if version (insert version ?\s)))))
576 641
577 ;;;###autoload 642 ;;;###autoload
578 (defun add-change-log-entry-other-window (&optional whoami file-name) 643 (defun add-change-log-entry-other-window (&optional whoami file-name)
579 "Find change log file in other window and add entry and item. 644 "Find change log file in other window and add entry and item.
580 This is just like `add-change-log-entry' except that it displays 645 This is just like `add-change-log-entry' except that it displays
583 (list current-prefix-arg 648 (list current-prefix-arg
584 (prompt-for-change-log-name)))) 649 (prompt-for-change-log-name))))
585 (add-change-log-entry whoami file-name t)) 650 (add-change-log-entry whoami file-name t))
586 ;;;###autoload (define-key ctl-x-4-map "a" 'add-change-log-entry-other-window) 651 ;;;###autoload (define-key ctl-x-4-map "a" 'add-change-log-entry-other-window)
587 652
653 (defvar add-log-indent-text 0)
654
655 (defun add-log-indent ()
656 (let* ((indent
657 (save-excursion
658 (beginning-of-line)
659 (skip-chars-forward " \t")
660 (cond
661 ((and (looking-at "\\(.*\\) [^ \n].*[^ \n] <.*>$")
662 ;; Matching the output of add-log-time-format is difficult,
663 ;; but I'll get it has at least two adjacent digits.
664 (string-match "[[:digit:]][[:digit:]]" (match-string 1)))
665 0)
666 ((looking-at "[^*(]")
667 (+ (current-left-margin) add-log-indent-text))
668 (t (current-left-margin)))))
669 (pos (save-excursion (indent-line-to indent) (point))))
670 (if (> pos (point)) (goto-char pos))))
671
672
673 (defvar smerge-resolve-function)
674
588 ;;;###autoload 675 ;;;###autoload
589 (define-derived-mode change-log-mode text-mode "Change Log" 676 (define-derived-mode change-log-mode text-mode "Change Log"
590 "Major mode for editing change logs; like Indented Text Mode. 677 "Major mode for editing change logs; like Indented Text Mode.
591 Prevents numeric backups and sets `left-margin' to 8 and `fill-column' to 74. 678 Prevents numeric backups and sets `left-margin' to 8 and `fill-column' to 74.
592 New log entries are usually made with \\[add-change-log-entry] or \\[add-change-log-entry-other-window]. 679 New log entries are usually made with \\[add-change-log-entry] or \\[add-change-log-entry-other-window].
593 Each entry behaves as a paragraph, and the entries for one day as a page. 680 Each entry behaves as a paragraph, and the entries for one day as a page.
594 Runs `change-log-mode-hook'." 681 Runs `change-log-mode-hook'.
682 \\{change-log-mode-map}"
595 (setq left-margin 8 683 (setq left-margin 8
596 fill-column 74 684 fill-column 74
597 indent-tabs-mode t 685 indent-tabs-mode t
598 tab-width 8) 686 tab-width 8)
599 (set (make-local-variable 'fill-paragraph-function) 687 (set (make-local-variable 'fill-paragraph-function)
600 'change-log-fill-paragraph) 688 'change-log-fill-paragraph)
601 (set (make-local-variable 'indent-line-function) 'indent-to-left-margin) 689 (set (make-local-variable 'indent-line-function) 'add-log-indent)
690 (set (make-local-variable 'tab-always-indent) nil)
602 ;; We really do want "^" in paragraph-start below: it is only the 691 ;; We really do want "^" in paragraph-start below: it is only the
603 ;; lines that begin at column 0 (despite the left-margin of 8) that 692 ;; lines that begin at column 0 (despite the left-margin of 8) that
604 ;; we are looking for. Adding `* ' allows eliding the blank line 693 ;; we are looking for. Adding `* ' allows eliding the blank line
605 ;; between entries for different files. 694 ;; between entries for different files.
606 (set (make-local-variable 'paragraph-start) "\\s *$\\|\f\\|^\\<") 695 (set (make-local-variable 'paragraph-start) "\\s *$\\|\f\\|^\\<")
717 ;; before the open brace. If so, advance forward. 806 ;; before the open brace. If so, advance forward.
718 (while (not (looking-at "{\\|\\(\\s *$\\)")) 807 (while (not (looking-at "{\\|\\(\\s *$\\)"))
719 (forward-line 1)) 808 (forward-line 1))
720 (or (eobp) 809 (or (eobp)
721 (forward-char 1)) 810 (forward-char 1))
722 (beginning-of-defun) 811 (let (maybe-beg)
723 (when (progn (end-of-defun) 812 ;; Try to find the containing defun.
724 (< location (point))) 813 (beginning-of-defun)
814 (end-of-defun)
815 ;; If the defun we found ends before the desired position,
816 ;; see if there's a DEFUN construct
817 ;; between that end and the desired position.
818 (when (save-excursion
819 (and (> location (point))
820 (re-search-forward "^DEFUN"
821 (save-excursion
822 (goto-char location)
823 (line-end-position))
824 t)
825 (re-search-forward "^{" nil t)
826 (setq maybe-beg (point))))
827 ;; If so, go to the end of that instead.
828 (goto-char maybe-beg)
829 (end-of-defun)))
830 ;; If the desired position is within the defun we found,
831 ;; find the function name.
832 (when (< location (point))
833 ;; Move back over function body.
725 (backward-sexp 1) 834 (backward-sexp 1)
726 (let (beg tem) 835 (let (beg)
727 836 ;; Skip back over typedefs and arglist.
837 ;; Stop at the function definition itself
838 ;; or at the line that follows end of function doc string.
728 (forward-line -1) 839 (forward-line -1)
729 ;; Skip back over typedefs of arglist.
730 (while (and (not (bobp)) 840 (while (and (not (bobp))
731 (looking-at "[ \t\n]")) 841 (looking-at "[ \t\n]")
842 (not (looking-back "[*]/)\n" (- (point) 4))))
732 (forward-line -1)) 843 (forward-line -1))
733 ;; See if this is using the DEFUN macro used in Emacs, 844 ;; If we found a doc string, this must be the DEFUN macro
734 ;; or the DEFUN macro used by the C library. 845 ;; used in Emacs. Move back to the DEFUN line.
735 (if (condition-case nil 846 (when (looking-back "[*]/)\n" (- (point) 4))
736 (and (save-excursion 847 (backward-sexp 1)
737 (end-of-line) 848 (beginning-of-line))
738 (while (= (preceding-char) ?\\) 849 ;; Is this a DEFUN construct? And is LOCATION in it?
739 (end-of-line 2)) 850 (if (and (looking-at "DEFUN\\b")
740 (backward-sexp 1) 851 (>= location (point)))
741 (beginning-of-line) 852 ;; DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory, ...) ==> Ffile_name_directory
742 (setq tem (point)) 853 ;; DEFUN(POSIX::STREAM-LOCK, stream lockp &key BLOCK SHARED START LENGTH) ==> POSIX::STREAM-LOCK
743 (looking-at "DEFUN\\b"))
744 (>= location tem))
745 (error nil))
746 (progn 854 (progn
747 (goto-char tem)
748 (down-list 1) 855 (down-list 1)
749 (if (= (char-after (point)) ?\") 856 (when (= (char-after (point)) ?\")
750 (progn 857 (forward-sexp 1)
751 (forward-sexp 1) 858 (search-forward ","))
752 (skip-chars-forward " ,"))) 859 (skip-syntax-forward " ")
753 (buffer-substring-no-properties 860 (buffer-substring-no-properties
754 (point) 861 (point)
755 (progn (forward-sexp 1) 862 (progn (search-forward ",")
863 (forward-char -1)
864 (skip-syntax-backward " ")
756 (point)))) 865 (point))))
757 (if (looking-at "^[+-]") 866 (if (looking-at "^[+-]")
867 ;; Objective-C
758 (change-log-get-method-definition) 868 (change-log-get-method-definition)
759 ;; Ordinary C function syntax. 869 ;; Ordinary C function syntax.
760 (setq beg (point)) 870 (setq beg (point))
761 (if (and 871 (if (and
762 ;; Protect against "Unbalanced parens" error. 872 ;; Protect against "Unbalanced parens" error.
793 ;; Now find the right beginning of the name. 903 ;; Now find the right beginning of the name.
794 ;; Include certain keywords if they 904 ;; Include certain keywords if they
795 ;; precede the name. 905 ;; precede the name.
796 (setq middle (point)) 906 (setq middle (point))
797 (forward-word -1) 907 (forward-word -1)
908 ;; Is this C++ method?
909 (when (and (< 2 middle)
910 (string= (buffer-substring (- middle 2)
911 middle)
912 "::"))
913 ;; Include "classname::".
914 (setq middle (point)))
798 ;; Ignore these subparts of a class decl 915 ;; Ignore these subparts of a class decl
799 ;; and move back to the class name itself. 916 ;; and move back to the class name itself.
800 (while (looking-at "public \\|private ") 917 (while (looking-at "public \\|private ")
801 (skip-chars-backward " \t:") 918 (skip-chars-backward " \t:")
802 (setq end (point)) 919 (setq end (point))
866 (match-string 1) 983 (match-string 1)
867 end)) 984 end))
868 (goto-char (match-end 0))) 985 (goto-char (match-end 0)))
869 986
870 (defun change-log-get-method-definition () 987 (defun change-log-get-method-definition ()
871 "For objective C, return the method name if we are in a method." 988 "For Objective C, return the method name if we are in a method."
872 (let ((change-log-get-method-definition-md "[")) 989 (let ((change-log-get-method-definition-md "["))
873 (save-excursion 990 (save-excursion
874 (if (re-search-backward "^@implementation\\s-*\\([A-Za-z_]*\\)" nil t) 991 (if (re-search-backward "^@implementation\\s-*\\([A-Za-z_]*\\)" nil t)
875 (change-log-get-method-definition-1 " "))) 992 (change-log-get-method-definition-1 " ")))
876 (save-excursion 993 (save-excursion
912 (replace-match (match-string 3) t t) 1029 (replace-match (match-string 3) t t)
913 (change-log-merge other-buf)))))))) 1030 (change-log-merge other-buf))))))))
914 1031
915 ;;;###autoload 1032 ;;;###autoload
916 (defun change-log-merge (other-log) 1033 (defun change-log-merge (other-log)
917 "Merge the contents of ChangeLog file OTHER-LOG with this buffer. 1034 "Merge the contents of change log file OTHER-LOG with this buffer.
918 Both must be found in Change Log mode (since the merging depends on 1035 Both must be found in Change Log mode (since the merging depends on
919 the appropriate motion commands). OTHER-LOG can be either a file name 1036 the appropriate motion commands). OTHER-LOG can be either a file name
920 or a buffer. 1037 or a buffer.
921 1038
922 Entries are inserted in chronological order. Both the current and 1039 Entries are inserted in chronological order. Both the current and
951 ;; merged. 1068 ;; merged.
952 (unless (or (bobp) 1069 (unless (or (bobp)
953 (and (= ?\n (char-before)) 1070 (and (= ?\n (char-before))
954 (or (<= (1- (point)) (point-min)) 1071 (or (<= (1- (point)) (point-min))
955 (= ?\n (char-before (1- (point))))))) 1072 (= ?\n (char-before (1- (point)))))))
956 (insert "\n")) 1073 (insert (if use-hard-newlines hard-newline "\n")))
957 ;; Move to the end of it to terminate outer loop. 1074 ;; Move to the end of it to terminate outer loop.
958 (with-current-buffer other-buf 1075 (with-current-buffer other-buf
959 (goto-char (point-max))) 1076 (goto-char (point-max)))
960 (insert-buffer-substring other-buf start))))))) 1077 (insert-buffer-substring other-buf start)))))))
961 1078
982 (aref date 0) 1099 (aref date 0)
983 zone)))))))) 1100 zone))))))))
984 1101
985 (provide 'add-log) 1102 (provide 'add-log)
986 1103
1104 ;;; arch-tag: 81eee6fc-088f-4372-a37f-80ad9620e762
987 ;;; add-log.el ends here 1105 ;;; add-log.el ends here