(decode_coding_charset): Check type of an element of
[bpt/emacs.git] / lisp / bookmark.el
CommitLineData
e8af40ee 1;;; bookmark.el --- set bookmarks, maybe annotate them, jump to them later
b3bf02fa 2
0d30b337 3;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 2001, 2002, 2003,
3da360a7 4;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
b3bf02fa 5
60d0378e
KF
6;; Author: Karl Fogel <kfogel@red-bean.com>
7;; Maintainer: Karl Fogel <kfogel@red-bean.com>
b3bf02fa 8;; Created: July, 1993
e3437989 9;; Keywords: bookmarks, placeholders, annotations
b3bf02fa
RS
10
11;; This file is part of GNU Emacs.
12
eb3fa2cf 13;; GNU Emacs is free software: you can redistribute it and/or modify
b3bf02fa 14;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
b3bf02fa
RS
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
eb3fa2cf 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
b578f267
EN
25
26;;; Commentary:
27
28;; This package is for setting "bookmarks" in files. A bookmark
29;; associates a string with a location in a certain file. Thus, you
30;; can navigate your way to that location by providing the string.
31;; See the "User Variables" section for customizations.
b3bf02fa
RS
32
33;; Thanks to David Bremner <bremner@cs.sfu.ca> for thinking of and
34;; then implementing the bookmark-current-bookmark idea. He even
d23e2c3f 35;; sent *patches*, bless his soul...
b3bf02fa
RS
36
37;; Thanks to Gregory M. Saunders <saunders@cis.ohio-state.edu> for
38;; fixing and improving bookmark-time-to-save-p.
39
e3437989
RS
40;; Thanks go to Andrew V. Klein <avk@cig.mot.com> for the code that
41;; sorts the alist before presenting it to the user (in bookmark-bmenu-list
d23e2c3f
KF
42;; and the menu-bar).
43
d22d6453
RS
44;; And much thanks to David Hughes <djh@harston.cv.com> for many small
45;; suggestions and the code to implement them (like
e3437989 46;; bookmark-bmenu-check-position, and some of the Lucid compatibility
d22d6453
RS
47;; stuff).
48
60d0378e 49;; Kudos (whatever they are) go to Jim Blandy <jimb@red-bean.com>
d23e2c3f
KF
50;; for his eminently sensible suggestion to separate bookmark-jump
51;; into bookmark-jump and bookmark-jump-noselect, which made many
52;; other things cleaner as well.
53
d22d6453
RS
54;; Thanks to Roland McGrath for encouragement and help with defining
55;; autoloads on the menu-bar.
56
2b911848 57;; Jonathan Stigelman <stig@hackvan.com> gave patches for default
d23e2c3f
KF
58;; values in bookmark-jump and bookmark-set. Everybody please keep
59;; all the keystrokes they save thereby and send them to him at the
60;; end of each year :-) (No, seriously, thanks Jonathan!)
61
e3437989
RS
62;; Buckets of gratitude to John Grabowski <johng@media.mit.edu> for
63;; thinking up the annotations feature and implementing it so well.
64
b3bf02fa
RS
65;; Based on info-bookmark.el, by Karl Fogel and Ken Olstad
66;; <olstad@msc.edu>.
67
4eadcdf8
RS
68;; Thanks to Mikio Nakajima <PBC01764@niftyserve.or.jp> for many bugs
69;; reported and fixed.
70
09fd6588
KF
71;; Thank you, Michael Kifer, for contributing the XEmacs support.
72
d22d6453 73;; Enough with the credits already, get on to the good stuff:
b3bf02fa 74
dbe99ae9 75;; FAVORITE CHINESE RESTAURANT:
b3bf02fa
RS
76;; Boy, that's a tough one. Probably Hong Min, or maybe Emperor's
77;; Choice (both in Chicago's Chinatown). Well, both. How about you?
e3437989 78\f
e8af40ee 79;;; Code:
b3bf02fa 80
b578f267 81(require 'pp)
2ef435bf 82(eval-when-compile (require 'cl))
b578f267 83
e3437989 84;;; Misc comments:
b3bf02fa 85;;
e3437989 86;; If variable bookmark-use-annotations is non-nil, an annotation is
dbe99ae9 87;; queried for when setting a bookmark.
11eb4275 88;;
d22d6453
RS
89;; The bookmark list is sorted lexically by default, but you can turn
90;; this off by setting bookmark-sort-flag to nil. If it is nil, then
91;; the list will be presented in the order it is recorded
92;; (chronologically), which is actually fairly useful as well.
b3bf02fa 93
4eadcdf8
RS
94;;; User Variables
95
bbf5eb28 96(defgroup bookmark nil
9848f0ca 97 "Setting, annotation and jumping to bookmarks."
bbf5eb28
RS
98 :group 'matching)
99
100
101(defcustom bookmark-use-annotations nil
fc22668d 102 "If non-nil, saving a bookmark queries for an annotation in a buffer."
bbf5eb28
RS
103 :type 'boolean
104 :group 'bookmark)
4eadcdf8
RS
105
106
bbf5eb28 107(defcustom bookmark-save-flag t
fc22668d 108 "Controls when Emacs saves bookmarks to a file.
9848f0ca 109--> nil means never save bookmarks, except when `bookmark-save' is
4eadcdf8
RS
110 explicitly called \(\\[bookmark-save]\).
111--> t means save bookmarks when Emacs is killed.
3b526bae 112--> Otherwise, it should be a number that is the frequency with which
4eadcdf8
RS
113 the bookmark list is saved \(i.e.: the number of times which
114 Emacs' bookmark list may be modified before it is automatically
115 saved.\). If it is a number, Emacs will also automatically save
116 bookmarks when it is killed.
117
118Therefore, the way to get it to save every time you make or delete a
119bookmark is to set this variable to 1 \(or 0, which produces the same
120behavior.\)
121
122To specify the file in which to save them, modify the variable
9848f0ca 123`bookmark-default-file', which is `~/.emacs.bmk' by default."
31fa1bd1 124 :type '(choice (const nil) integer (other t))
bbf5eb28 125 :group 'bookmark)
4eadcdf8
RS
126
127
128(defconst bookmark-old-default-file "~/.emacs-bkmrks"
9848f0ca 129 "*The `.emacs.bmk' file used to be called this name.")
4eadcdf8
RS
130
131
132;; defvarred to avoid a compilation warning:
133(defvar bookmark-file nil
134 "Old name for `bookmark-default-file'.")
135
bbf5eb28 136(defcustom bookmark-default-file
4eadcdf8
RS
137 (if bookmark-file
138 ;; In case user set `bookmark-file' in her .emacs:
139 bookmark-file
88fb0aaa 140 (convert-standard-filename "~/.emacs.bmk"))
fc22668d 141 "File in which to save bookmarks by default."
bbf5eb28
RS
142 :type 'file
143 :group 'bookmark)
4eadcdf8
RS
144
145
bbf5eb28 146(defcustom bookmark-version-control 'nospecial
fc22668d 147 "Whether or not to make numbered backups of the bookmark file.
4eadcdf8
RS
148It can have four values: t, nil, `never', and `nospecial'.
149The first three have the same meaning that they do for the
150variable `version-control', and the final value `nospecial' means just
bbf5eb28 151use the value of `version-control'."
31fa1bd1
AS
152 :type '(choice (const nil) (const never) (const nospecial)
153 (other t))
bbf5eb28 154 :group 'bookmark)
4eadcdf8
RS
155
156
bbf5eb28 157(defcustom bookmark-completion-ignore-case t
fc22668d 158 "Non-nil means bookmark functions ignore case in completion."
bbf5eb28
RS
159 :type 'boolean
160 :group 'bookmark)
4eadcdf8
RS
161
162
bbf5eb28 163(defcustom bookmark-sort-flag t
fc22668d 164 "Non-nil means that bookmarks will be displayed sorted by bookmark name.
9848f0ca 165Otherwise they will be displayed in LIFO order (that is, most
bbf5eb28
RS
166recently set ones come first, oldest ones come last)."
167 :type 'boolean
168 :group 'bookmark)
4eadcdf8
RS
169
170
bbf5eb28 171(defcustom bookmark-automatically-show-annotations t
fc22668d 172 "Non-nil means show annotations when jumping to a bookmark."
bbf5eb28
RS
173 :type 'boolean
174 :group 'bookmark)
4eadcdf8
RS
175
176
bbf5eb28 177(defcustom bookmark-bmenu-file-column 30
fc22668d 178 "Column at which to display filenames in a buffer listing bookmarks.
bbf5eb28
RS
179You can toggle whether files are shown with \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-toggle-filenames]."
180 :type 'integer
181 :group 'bookmark)
4eadcdf8
RS
182
183
bbf5eb28 184(defcustom bookmark-bmenu-toggle-filenames t
fc22668d 185 "Non-nil means show filenames when listing bookmarks.
4eadcdf8 186This may result in truncated bookmark names. To disable this, put the
9848f0ca 187following in your `.emacs' file:
4eadcdf8 188
bbf5eb28
RS
189\(setq bookmark-bmenu-toggle-filenames nil\)"
190 :type 'boolean
191 :group 'bookmark)
4eadcdf8
RS
192
193
bbf5eb28 194(defcustom bookmark-menu-length 70
fc22668d 195 "Maximum length of a bookmark name displayed on a popup menu."
bbf5eb28 196 :type 'integer
85d457c6 197 :group 'bookmark)
4eadcdf8
RS
198
199
37789292
RF
200(defface bookmark-menu-heading
201 '((t (:inherit font-lock-type-face)))
202 "Face used to highlight the heading in bookmark menu buffers."
203 :group 'bookmark
204 :version "22.1")
205
206
4eadcdf8 207;;; No user-serviceable parts beyond this point.
b3bf02fa
RS
208
209;; Added for lucid emacs compatibility, db
210(or (fboundp 'defalias) (fset 'defalias 'fset))
211
d22d6453 212;; suggested for lucid compatibility by david hughes:
4eadcdf8 213(or (fboundp 'frame-height) (defalias 'frame-height 'screen-height))
d22d6453 214
e3437989
RS
215\f
216;;; Keymap stuff:
b3bf02fa 217
77bc05c7
RS
218;; Set up these bindings dumping time *only*;
219;; if the user alters them, don't override the user when loading bookmark.el.
220
e1321788
JL
221;;;###autoload (define-key ctl-x-r-map "b" 'bookmark-jump)
222;;;###autoload (define-key ctl-x-r-map "m" 'bookmark-set)
223;;;###autoload (define-key ctl-x-r-map "l" 'bookmark-bmenu-list)
36ae4ff7 224
d22d6453 225;;;###autoload
79363d93
SM
226(defvar bookmark-map
227 (let ((map (make-sparse-keymap)))
228 ;; Read the help on all of these functions for details...
229 (define-key map "x" 'bookmark-set)
230 (define-key map "m" 'bookmark-set) ;"m"ark
231 (define-key map "j" 'bookmark-jump)
232 (define-key map "g" 'bookmark-jump) ;"g"o
233 (define-key map "o" 'bookmark-jump-other-window)
234 (define-key map "i" 'bookmark-insert)
235 (define-key map "e" 'edit-bookmarks)
236 (define-key map "f" 'bookmark-insert-location) ;"f"ind
237 (define-key map "r" 'bookmark-rename)
238 (define-key map "d" 'bookmark-delete)
239 (define-key map "l" 'bookmark-load)
240 (define-key map "w" 'bookmark-write)
241 (define-key map "s" 'bookmark-save)
242 map)
9aef3b21
RS
243 "Keymap containing bindings to bookmark functions.
244It is not bound to any key by default: to bind it
245so that you have a bookmark prefix, just use `global-set-key' and bind a
246key of your choice to `bookmark-map'. All interactive bookmark
b3bf02fa
RS
247functions have a binding in this keymap.")
248
79363d93 249;;;###autoload (fset 'bookmark-map bookmark-map)
e3437989 250
e3437989
RS
251\f
252;;; Core variables and data structures:
7e2d009d 253(defvar bookmark-alist ()
e3437989 254 "Association list of bookmarks and their records.
7e2d009d 255You probably don't want to change the value of this alist yourself;
4eadcdf8
RS
256instead, let the various bookmark functions do it for you.
257
258The format of the alist is
259
260 \(BOOKMARK1 BOOKMARK2 ...\)
261
43f8b275 262where each BOOKMARK is of the form
4eadcdf8 263
43f8b275 264 (NAME PARAM-ALIST) or (NAME . PARAM-ALIST)
4eadcdf8 265
43f8b275
SM
266where the first form is the old deprecated one and the second is
267the new favored one. PARAM-ALIST is typically of the form:
268
269 ((filename . FILE)
270 (front-context-string . FRONT-STR)
271 (rear-context-string . REAR-STR)
272 (position . POS)
273 (annotation . ANNOTATION)))")
7e2d009d 274
e3437989 275
d22d6453
RS
276(defvar bookmarks-already-loaded nil)
277
e3437989 278
b3bf02fa 279;; more stuff added by db.
d22d6453 280
dbe99ae9 281(defvar bookmark-current-bookmark nil
9aef3b21
RS
282 "Name of bookmark most recently used in the current file.
283It is buffer local, used to make moving a bookmark forward
8027e2ad 284through a file easier.")
b3bf02fa
RS
285
286(make-variable-buffer-local 'bookmark-current-bookmark)
287
e3437989 288
b3bf02fa 289(defvar bookmark-alist-modification-count 0
9aef3b21 290 "Number of modifications to bookmark list since it was last saved.")
b3bf02fa 291
e3437989 292
e3437989 293(defvar bookmark-search-size 16
9aef3b21 294 "Length of the context strings recorded on either side of a bookmark.")
b3bf02fa 295
e3437989 296
b3bf02fa
RS
297(defvar bookmark-current-point 0)
298(defvar bookmark-yank-point 0)
299(defvar bookmark-current-buffer nil)
300
f8e1f213 301(defvar Info-suffix-list)
e3437989
RS
302\f
303;; Helper functions.
304
305;; Only functions on this page and the next one (file formats) need to
306;; know anything about the format of bookmark-alist entries.
307;; Everyone else should go through them.
308
f9bf6950 309
e3437989 310(defun bookmark-name-from-full-record (full-record)
4eadcdf8 311 "Return name of FULL-RECORD \(an alist element instead of a string\)."
e3437989
RS
312 (car full-record))
313
314
315(defun bookmark-all-names ()
316 "Return a list of all current bookmark names."
317 (bookmark-maybe-load-default-file)
43f8b275 318 (mapcar 'bookmark-name-from-full-record bookmark-alist))
e3437989
RS
319
320
2ef435bf 321(defun bookmark-get-bookmark (bookmark &optional noerror)
43f8b275
SM
322 "Return the bookmark record corresponding to BOOKMARK.
323If BOOKMARK is already a bookmark record, just return it,
324Otherwise look for the corresponding bookmark in `bookmark-alist'."
325 (cond
326 ((consp bookmark) bookmark)
327 ((stringp bookmark)
2ef435bf
SM
328 (or (assoc-string bookmark bookmark-alist bookmark-completion-ignore-case)
329 (unless noerror (error "Invalid bookmark %s" bookmark))))))
e3437989
RS
330
331
332(defun bookmark-get-bookmark-record (bookmark)
d32ff76a 333 "Return the guts of the entry for BOOKMARK in `bookmark-alist'.
e3437989 334That is, all information but the name."
2ef435bf 335 (let ((alist (cdr (bookmark-get-bookmark bookmark))))
43f8b275
SM
336 ;; The bookmark objects can either look like (NAME ALIST) or
337 ;; (NAME . ALIST), so we have to distinguish the two here.
338 (if (and (null (cdr alist)) (consp (caar alist)))
339 (car alist) alist)))
e3437989
RS
340
341
342(defun bookmark-set-name (bookmark newname)
343 "Set BOOKMARK's name to NEWNAME."
91169ba7
RS
344 (setcar
345 (if (stringp bookmark) (bookmark-get-bookmark bookmark) bookmark)
346 newname))
e3437989 347
02a5ba27
SM
348(defun bookmark-prop-get (bookmark prop)
349 "Return the property PROP of BOOKMARK, or nil if none."
350 (cdr (assq prop (bookmark-get-bookmark-record bookmark))))
351
352(defun bookmark-prop-set (bookmark prop val)
353 "Set the property PROP of BOOKMARK to VAL."
354 (let ((cell (assq prop (bookmark-get-bookmark-record bookmark))))
355 (if cell
356 (setcdr cell val)
357 (nconc (bookmark-get-bookmark-record bookmark)
358 (list (cons prop val))))))
e3437989
RS
359
360(defun bookmark-get-annotation (bookmark)
361 "Return the annotation of BOOKMARK, or nil if none."
02a5ba27 362 (bookmark-prop-get bookmark 'annotation))
e3437989
RS
363
364(defun bookmark-set-annotation (bookmark ann)
4eadcdf8 365 "Set the annotation of BOOKMARK to ANN."
02a5ba27 366 (bookmark-prop-set bookmark 'annotation ann))
e3437989
RS
367
368
369(defun bookmark-get-filename (bookmark)
370 "Return the full filename of BOOKMARK."
02a5ba27 371 (bookmark-prop-get bookmark 'filename))
e3437989
RS
372
373
374(defun bookmark-set-filename (bookmark filename)
375 "Set the full filename of BOOKMARK to FILENAME."
43f8b275 376 (bookmark-prop-set bookmark 'filename filename))
e3437989
RS
377
378
379(defun bookmark-get-position (bookmark)
380 "Return the position \(i.e.: point\) of BOOKMARK."
02a5ba27 381 (bookmark-prop-get bookmark 'position))
e3437989
RS
382
383
384(defun bookmark-set-position (bookmark position)
385 "Set the position \(i.e.: point\) of BOOKMARK to POSITION."
02a5ba27 386 (bookmark-prop-set bookmark 'position position))
e3437989
RS
387
388
389(defun bookmark-get-front-context-string (bookmark)
390 "Return the front-context-string of BOOKMARK."
02a5ba27 391 (bookmark-prop-get bookmark 'front-context-string))
e3437989
RS
392
393
394(defun bookmark-set-front-context-string (bookmark string)
395 "Set the front-context-string of BOOKMARK to STRING."
02a5ba27 396 (bookmark-prop-set bookmark 'front-context-string string))
e3437989
RS
397
398
399(defun bookmark-get-rear-context-string (bookmark)
400 "Return the rear-context-string of BOOKMARK."
02a5ba27 401 (bookmark-prop-get bookmark 'rear-context-string))
e3437989
RS
402
403
404(defun bookmark-set-rear-context-string (bookmark string)
405 "Set the rear-context-string of BOOKMARK to STRING."
02a5ba27 406 (bookmark-prop-set bookmark 'rear-context-string string))
e3437989
RS
407
408
1666a6b3 409(defun bookmark-get-handler (bookmark)
02a5ba27 410 (bookmark-prop-get bookmark 'handler))
e3437989 411
4c0b5ad1
KF
412(defvar bookmark-history nil
413 "The history list for bookmark functions.")
414
415
e3437989
RS
416(defun bookmark-completing-read (prompt &optional default)
417 "Prompting with PROMPT, read a bookmark name in completion.
418PROMPT will get a \": \" stuck on the end no matter what, so you
419probably don't want to include one yourself.
420Optional second arg DEFAULT is a string to return if the user enters
421the empty string."
422 (bookmark-maybe-load-default-file) ; paranoia
175d0960
SM
423 (if (listp last-nonmenu-event)
424 (bookmark-menu-popup-paned-menu t prompt (bookmark-all-names))
425 (let* ((completion-ignore-case bookmark-completion-ignore-case)
426 (default default)
427 (prompt (if default
428 (concat prompt (format " (%s): " default))
429 (concat prompt ": ")))
430 (str
431 (completing-read prompt
432 bookmark-alist
433 nil
434 0
435 nil
436 'bookmark-history)))
437 (if (string-equal "" str) default str))))
e3437989
RS
438
439
4c0b5ad1
KF
440(defmacro bookmark-maybe-historicize-string (string)
441 "Put STRING into the bookmark prompt history, if caller non-interactive.
442We need this because sometimes bookmark functions are invoked from
443menus, so `completing-read' never gets a chance to set `bookmark-history'."
dbe99ae9
SS
444 `(or
445 (interactive-p)
446 (setq bookmark-history (cons ,string bookmark-history))))
4c0b5ad1 447
43f8b275 448(defvar bookmark-make-record-function 'bookmark-make-record-default
e0385bf4
KF
449 "A function that should be called to create a bookmark record.
450Modes may set this variable buffer-locally to enable bookmarking of
451locations that should be treated specially, such as Info nodes,
452news posts, images, pdf documents, etc.
1666a6b3 453
32a091dd 454The function will be called with no arguments.
43f8b275
SM
455It should signal a user error if it is unable to construct a record for
456the current location.
136894c8
SM
457
458The returned record should be a cons cell of the form (NAME . ALIST)
459where ALIST is as described in `bookmark-alist' and may typically contain
460a special cons (handler . SOME-FUNCTION) which sets the handler function
461that should be used to open this bookmark instead of
43f8b275
SM
462`bookmark-default-handler'. The handler should follow the same calling
463convention as the one used by `bookmark-default-handler'.
136894c8
SM
464
465NAME is a suggested name for the constructed bookmark. It can be nil
43f8b275
SM
466in which case a default heuristic will be used. The function can also
467equivalently just return ALIST without NAME.")
136894c8
SM
468
469(defun bookmark-make-record ()
470 "Return a new bookmark record (NAME . ALIST) for the current location."
471 (let ((record (funcall bookmark-make-record-function)))
472 ;; Set up default name.
473 (if (stringp (car record))
474 ;; The function already provided a default name.
475 record
476 (if (car record) (push nil record))
477 (setcar record (or bookmark-current-bookmark (bookmark-buffer-name)))
478 record)))
479
480(defun bookmark-store (name alist no-overwrite)
481 "Store the bookmark NAME with data ALIST.
482If NO-OVERWRITE is non-nil and another bookmark of the same name already
483exists in `bookmark-alist', record the new bookmark without throwing away the
484old one."
e3437989 485 (bookmark-maybe-load-default-file)
88415bfc 486 (let ((stripped-name (copy-sequence name)))
4211e434 487 (or (featurep 'xemacs)
09fd6588
KF
488 ;; XEmacs's `set-text-properties' doesn't work on
489 ;; free-standing strings, apparently.
490 (set-text-properties 0 (length stripped-name) nil stripped-name))
2ef435bf
SM
491 (if (and (not no-overwrite)
492 (bookmark-get-bookmark stripped-name 'noerror))
3b526bae 493 ;; already existing bookmark under that name and
88415bfc 494 ;; no prefix arg means just overwrite old bookmark
43f8b275
SM
495 ;; Use the new (NAME . ALIST) format.
496 (setcdr (bookmark-get-bookmark stripped-name) alist)
dbe99ae9 497
88415bfc
KH
498 ;; otherwise just cons it onto the front (either the bookmark
499 ;; doesn't exist already, or there is no prefix arg. In either
500 ;; case, we want the new bookmark consed onto the alist...)
dbe99ae9 501
43f8b275 502 (push (cons stripped-name alist) bookmark-alist))
dbe99ae9 503
88415bfc
KH
504 ;; Added by db
505 (setq bookmark-current-bookmark stripped-name)
506 (setq bookmark-alist-modification-count
507 (1+ bookmark-alist-modification-count))
508 (if (bookmark-time-to-save-p)
136894c8 509 (bookmark-save))
e3437989 510
136894c8
SM
511 (setq bookmark-current-bookmark stripped-name)
512 (bookmark-bmenu-surreptitiously-rebuild-list)))
e3437989 513
43f8b275 514(defun bookmark-make-record-default (&optional point-only)
32a091dd 515 "Return the record describing the location of a new bookmark.
e3437989 516Must be at the correct position in the buffer in which the bookmark is
43f8b275
SM
517being set.
518If POINT-ONLY is non-nil, then only return the subset of the
519record that pertains to the location within the buffer."
520 `(,@(unless point-only `((filename . ,(bookmark-buffer-file-name))))
32a091dd
SM
521 (front-context-string
522 . ,(if (>= (- (point-max) (point)) bookmark-search-size)
523 (buffer-substring-no-properties
524 (point)
525 (+ (point) bookmark-search-size))
526 nil))
527 (rear-context-string
528 . ,(if (>= (- (point) (point-min)) bookmark-search-size)
529 (buffer-substring-no-properties
530 (point)
531 (- (point) bookmark-search-size))
532 nil))
533 (position . ,(point))))
dbe99ae9 534
e3437989
RS
535\f
536;;; File format stuff
537
538;; The OLD format of the bookmark-alist was:
539;;
185ae1f1
SM
540;; ((BOOKMARK-NAME . (FILENAME
541;; STRING-IN-FRONT
542;; STRING-BEHIND
543;; POINT))
e3437989
RS
544;; ...)
545;;
546;; The NEW format of the bookmark-alist is:
547;;
185ae1f1
SM
548;; ((BOOKMARK-NAME (filename . FILENAME)
549;; (front-context-string . STRING-IN-FRONT)
550;; (rear-context-string . STRING-BEHIND)
551;; (position . POINT)
552;; (annotation . ANNOTATION)
553;; (whatever . VALUE)
554;; ...
555;; ))
e3437989
RS
556;; ...)
557;;
558;;
559;; I switched to using an internal as well as external alist because I
560;; felt that would be a more flexible framework in which to add
561;; features. It means that the order in which values appear doesn't
562;; matter, and it means that arbitrary values can be added without
563;; risk of interfering with existing ones.
564;;
565;; BOOKMARK-NAME is the string the user gives the bookmark and
dbe99ae9 566;; accesses it by from then on.
e3437989
RS
567;;
568;; FILENAME is the location of the file in which the bookmark is set.
569;;
570;; STRING-IN-FRONT is a string of `bookmark-search-size' chars of
571;; context in front of the point at which the bookmark is set.
572;;
dbe99ae9 573;; STRING-BEHIND is the same thing, but after the point.
e3437989
RS
574;;
575;; The context strings exist so that modifications to a file don't
dbe99ae9 576;; necessarily cause a bookmark's position to be invalidated.
e3437989
RS
577;; bookmark-jump will search for STRING-BEHIND and STRING-IN-FRONT in
578;; case the file has changed since the bookmark was set. It will
579;; attempt to place the user before the changes, if there were any.
a15269c0 580;; ANNOTATION is the annotation for the bookmark; it may not exist
e3437989
RS
581;; (for backward compatibility), be nil (no annotation), or be a
582;; string.
e3437989
RS
583
584
585(defconst bookmark-file-format-version 1
586 "The current version of the format used by bookmark files.
587You should never need to change this.")
588
589
590(defconst bookmark-end-of-version-stamp-marker
591 "-*- End Of Bookmark File Format Version Stamp -*-\n"
592 "This string marks the end of the version stamp in a bookmark file.")
593
594
595(defun bookmark-alist-from-buffer ()
d32ff76a 596 "Return a `bookmark-alist' (in any format) from the current buffer.
e3437989
RS
597The buffer must of course contain bookmark format information.
598Does not care from where in the buffer it is called, and does not
599affect point."
600 (save-excursion
601 (goto-char (point-min))
602 (if (search-forward bookmark-end-of-version-stamp-marker nil t)
603 (read (current-buffer))
604 ;; Else we're dealing with format version 0
605 (if (search-forward "(" nil t)
606 (progn
607 (forward-char -1)
608 (read (current-buffer)))
609 ;; Else no hope of getting information here.
a3ad20c2 610 (error "Not bookmark format")))))
e3437989
RS
611
612
613(defun bookmark-upgrade-version-0-alist (old-list)
4eadcdf8 614 "Upgrade a version 0 alist OLD-LIST to the current version."
e3437989
RS
615 (mapcar
616 (lambda (bookmark)
617 (let* ((name (car bookmark))
618 (record (car (cdr bookmark)))
619 (filename (nth 0 record))
620 (front-str (nth 1 record))
621 (rear-str (nth 2 record))
622 (position (nth 3 record))
623 (ann (nth 4 record)))
624 (list
625 name
8a946354
SS
626 `((filename . ,filename)
627 (front-context-string . ,(or front-str ""))
628 (rear-context-string . ,(or rear-str ""))
629 (position . ,position)
630 (annotation . ,ann)))))
e3437989
RS
631 old-list))
632
633
634(defun bookmark-upgrade-file-format-from-0 ()
635 "Upgrade a bookmark file of format 0 (the original format) to format 1.
d32ff76a 636This expects to be called from `point-min' in a bookmark file."
e3437989
RS
637 (message "Upgrading bookmark format from 0 to %d..."
638 bookmark-file-format-version)
639 (let* ((old-list (bookmark-alist-from-buffer))
640 (new-list (bookmark-upgrade-version-0-alist old-list)))
641 (delete-region (point-min) (point-max))
642 (bookmark-insert-file-format-version-stamp)
643 (pp new-list (current-buffer))
644 (save-buffer))
645 (goto-char (point-min))
60d0378e 646 (message "Upgrading bookmark format from 0 to %d...done"
e3437989
RS
647 bookmark-file-format-version)
648 )
649
650
651(defun bookmark-grok-file-format-version ()
652 "Return an integer which is the file-format version of this bookmark file.
d32ff76a 653This expects to be called from `point-min' in a bookmark file."
e3437989
RS
654 (if (looking-at "^;;;;")
655 (save-excursion
656 (save-match-data
657 (re-search-forward "[0-9]")
658 (forward-char -1)
659 (read (current-buffer))))
660 ;; Else this is format version 0, the original one, which didn't
661 ;; even have version stamps.
662 0))
663
664
665(defun bookmark-maybe-upgrade-file-format ()
666 "Check the file-format version of this bookmark file.
667If the version is not up-to-date, upgrade it automatically.
d32ff76a 668This expects to be called from `point-min' in a bookmark file."
e3437989
RS
669 (let ((version (bookmark-grok-file-format-version)))
670 (cond
671 ((= version bookmark-file-format-version)
672 ) ; home free -- version is current
673 ((= version 0)
674 (bookmark-upgrade-file-format-from-0))
675 (t
a3ad20c2 676 (error "Bookmark file format version strangeness")))))
e3437989
RS
677
678
679(defun bookmark-insert-file-format-version-stamp ()
5e0e5feb 680 "Insert text indicating current version of bookmark file format."
e3437989
RS
681 (insert
682 (format ";;;; Emacs Bookmark Format Version %d ;;;;\n"
683 bookmark-file-format-version))
684 (insert ";;; This format is meant to be slightly human-readable;\n"
685 ";;; nevertheless, you probably don't want to edit it.\n"
686 ";;; "
687 bookmark-end-of-version-stamp-marker))
688
689
690;;; end file-format stuff
691
692\f
9a9f1fdd
KF
693;;; Generic helpers.
694
695(defun bookmark-maybe-message (fmt &rest args)
696 "Apply `message' to FMT and ARGS, but only if the display is fast enough."
697 (if (>= baud-rate 9600)
698 (apply 'message fmt args)))
699
700\f
e3437989
RS
701;;; Core code:
702
fc22668d
SM
703(defvar bookmark-minibuffer-read-name-map
704 (let ((map (make-sparse-keymap)))
705 (set-keymap-parent map minibuffer-local-map)
706 (define-key map "\C-w" 'bookmark-yank-word)
707 ;; This C-u binding might not be very useful any more now that we
708 ;; provide access to the default via the standard M-n binding.
709 ;; Maybe we should just remove it? --Stef-08
710 (define-key map "\C-u" 'bookmark-insert-current-bookmark)
711 map))
712
d22d6453 713;;;###autoload
4eadcdf8
RS
714(defun bookmark-set (&optional name parg)
715 "Set a bookmark named NAME inside a file.
716If name is nil, then the user will be prompted.
9aef3b21
RS
717With prefix arg, will not overwrite a bookmark that has the same name
718as NAME if such a bookmark already exists, but instead will \"push\"
719the new bookmark onto the bookmark alist. Thus the most recently set
720bookmark with name NAME would be the one in effect at any given time,
721but the others are still there, should you decide to delete the most
722recent one.
b3bf02fa
RS
723
724To yank words from the text of the buffer and use them as part of the
9aef3b21 725bookmark name, type C-w while setting a bookmark. Successive C-w's
b3bf02fa
RS
726yank successive words.
727
4c0b5ad1
KF
728Typing C-u inserts the name of the last bookmark used in the buffer
729\(as an aid in using a single bookmark name to track your progress
730through a large file\). If no bookmark was used, then C-u inserts the
731name of the file being visited.
b3bf02fa
RS
732
733Use \\[bookmark-delete] to remove bookmarks \(you give it a name,
734and it removes only the first instance of a bookmark with that name from
735the list of bookmarks.\)"
4eadcdf8 736 (interactive (list nil current-prefix-arg))
136894c8
SM
737 (let* ((record (bookmark-make-record))
738 (default (car record)))
739
740 (bookmark-maybe-load-default-file)
741
742 (setq bookmark-current-point (point))
743 (setq bookmark-yank-point (point))
744 (setq bookmark-current-buffer (current-buffer))
745
746 (let ((str
747 (or name
748 (read-from-minibuffer
749 (format "Set bookmark (%s): " default)
750 nil
751 bookmark-minibuffer-read-name-map
752 nil nil default))))
753 (and (string-equal str "") (setq str default))
754 (bookmark-store str (cdr record) parg)
0f219a97 755
136894c8
SM
756 ;; Ask for an annotation buffer for this bookmark
757 (if bookmark-use-annotations
758 (bookmark-edit-annotation str)
759 (goto-char bookmark-current-point)))))
e3437989
RS
760
761(defun bookmark-kill-line (&optional newline-too)
762 "Kill from point to end of line.
763If optional arg NEWLINE-TOO is non-nil, delete the newline too.
d32ff76a 764Does not affect the kill ring."
e3437989
RS
765 (let ((eol (save-excursion (end-of-line) (point))))
766 (delete-region (point) eol)
767 (if (and newline-too (looking-at "\n"))
768 (delete-char 1))))
769
770
4c0b5ad1 771;; Defvars to avoid compilation warnings:
a7e83b26
SM
772(defvar bookmark-annotation-name nil
773 "Variable holding the name of the bookmark.
774This is used in `bookmark-edit-annotation' to record the bookmark
775whose annotation is being edited.")
e3437989
RS
776
777
778(defun bookmark-default-annotation-text (bookmark)
779 (concat "# Type the annotation for bookmark '" bookmark "' here.\n"
780 "# All lines which start with a '#' will be deleted.\n"
781 "# Type C-c C-c when done.\n#\n"
782 "# Author: " (user-full-name) " <" (user-login-name) "@"
783 (system-name) ">\n"
784 "# Date: " (current-time-string) "\n"))
785
786
a7e83b26 787(defvar bookmark-edit-annotation-text-func 'bookmark-default-annotation-text
5e0e5feb 788 "Function to return default text to use for a bookmark annotation.
d32ff76a 789It takes one argument, the name of the bookmark, as a string.")
a7e83b26
SM
790(define-obsolete-variable-alias 'bookmark-read-annotation-text-func
791 'bookmark-edit-annotation-text-func "23.1")
e3437989 792
a7e83b26
SM
793(defvar bookmark-edit-annotation-mode-map
794 (let ((map (make-sparse-keymap)))
795 (set-keymap-parent map text-mode-map)
796 (define-key map "\C-c\C-c" 'bookmark-send-edited-annotation)
797 map)
e3437989
RS
798 "Keymap for editing an annotation of a bookmark.")
799
800
e3437989
RS
801(defun bookmark-edit-annotation-mode (bookmark)
802 "Mode for editing the annotation of bookmark BOOKMARK.
803When you have finished composing, type \\[bookmark-send-annotation].
804
1666a6b3 805\\{bookmark-edit-annotation-mode-map}"
e3437989
RS
806 (interactive)
807 (kill-all-local-variables)
808 (make-local-variable 'bookmark-annotation-name)
809 (setq bookmark-annotation-name bookmark)
810 (use-local-map bookmark-edit-annotation-mode-map)
dc5dcc00
JB
811 (setq major-mode 'bookmark-edit-annotation-mode
812 mode-name "Edit Bookmark Annotation")
a7e83b26 813 (insert (funcall bookmark-edit-annotation-text-func bookmark))
e3437989 814 (let ((annotation (bookmark-get-annotation bookmark)))
91169ba7 815 (if (and annotation (not (string-equal annotation "")))
e3437989 816 (insert annotation)))
f33cee85 817 (run-mode-hooks 'text-mode-hook))
e3437989
RS
818
819
820(defun bookmark-send-edited-annotation ()
dc5dcc00
JB
821 "Use buffer contents as annotation for a bookmark.
822Lines beginning with `#' are ignored."
e3437989
RS
823 (interactive)
824 (if (not (eq major-mode 'bookmark-edit-annotation-mode))
a3ad20c2 825 (error "Not in bookmark-edit-annotation-mode"))
e3437989
RS
826 (goto-char (point-min))
827 (while (< (point) (point-max))
828 (if (looking-at "^#")
829 (bookmark-kill-line t)
830 (forward-line 1)))
fc22668d
SM
831 ;; Take no chances with text properties.
832 (let ((annotation (buffer-substring-no-properties (point-min) (point-max)))
e3437989
RS
833 (bookmark bookmark-annotation-name))
834 (bookmark-set-annotation bookmark annotation)
835 (bookmark-bmenu-surreptitiously-rebuild-list)
836 (goto-char bookmark-current-point))
837 (kill-buffer (current-buffer)))
838
839
840(defun bookmark-edit-annotation (bookmark)
841 "Pop up a buffer for editing bookmark BOOKMARK's annotation."
175d0960
SM
842 (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*"))
843 (bookmark-edit-annotation-mode bookmark))
e3437989 844
b3bf02fa
RS
845
846(defun bookmark-insert-current-bookmark ()
d32ff76a 847 "Insert this buffer's value of `bookmark-current-bookmark'.
5e0e5feb 848Default to file name if it's nil."
b3bf02fa
RS
849 (interactive)
850 (let ((str
fc22668d
SM
851 (with-current-buffer bookmark-current-buffer
852 (or bookmark-current-bookmark
853 (bookmark-buffer-name)))))
e3437989
RS
854 (insert str)))
855
b3bf02fa 856
4cd51172 857(defun bookmark-buffer-name ()
d4432055 858 "Return the name of the current buffer's file, non-directory."
4cd51172 859 (cond
4cd51172
RS
860 ;; Or are we a file?
861 (buffer-file-name (file-name-nondirectory buffer-file-name))
862 ;; Or are we a directory?
863 ((and (boundp 'dired-directory) dired-directory)
864 (let* ((dirname (if (stringp dired-directory)
865 dired-directory
866 (car dired-directory)))
867 (idx (1- (length dirname))))
868 ;; Strip the trailing slash.
869 (if (= ?/ (aref dirname idx))
870 (file-name-nondirectory (substring dirname 0 idx))
871 ;; Else return the current-buffer
872 (buffer-name (current-buffer)))))
873 ;; If all else fails, use the buffer's name.
874 (t
875 (buffer-name (current-buffer)))))
876
877
b3bf02fa
RS
878(defun bookmark-yank-word ()
879 (interactive)
880 ;; get the next word from the buffer and append it to the name of
881 ;; the bookmark currently being set.
43f8b275
SM
882 (let ((string (with-current-buffer bookmark-current-buffer
883 (goto-char bookmark-yank-point)
884 (buffer-substring-no-properties
885 (point)
886 (progn
887 (forward-word 1)
888 (setq bookmark-yank-point (point)))))))
b3bf02fa
RS
889 (insert string)))
890
b3bf02fa 891(defun bookmark-buffer-file-name ()
d4432055 892 "Return the current buffer's file in a way useful for bookmarks."
3889f0fa
SM
893 ;; Abbreviate the path, both so it's shorter and so it's more
894 ;; portable. E.g., the user's home dir might be a different
895 ;; path on different machines, but "~/" will still reach it.
896 (abbreviate-file-name
897 (cond
898 (buffer-file-name buffer-file-name)
899 ((and (boundp 'dired-directory) dired-directory)
900 (if (stringp dired-directory)
901 dired-directory
902 (car dired-directory)))
903 (t (error "Buffer not visiting a file or directory")))))
e3437989
RS
904
905
e3437989 906(defun bookmark-maybe-load-default-file ()
d22d6453
RS
907 (and (not bookmarks-already-loaded)
908 (null bookmark-alist)
e3437989
RS
909 (prog2
910 (and
911 ;; Possibly the old bookmark file, "~/.emacs-bkmrks", needs
912 ;; to be renamed.
913 (file-exists-p (expand-file-name bookmark-old-default-file))
914 (not (file-exists-p (expand-file-name bookmark-default-file)))
915 (rename-file (expand-file-name bookmark-old-default-file)
916 (expand-file-name bookmark-default-file)))
917 ;; return t so the `and' will continue...
918 t)
dbe99ae9 919
e3437989 920 (file-readable-p (expand-file-name bookmark-default-file))
91169ba7
RS
921 (bookmark-load bookmark-default-file t t)
922 (setq bookmarks-already-loaded t)))
d22d6453 923
e3437989 924
d22d6453
RS
925(defun bookmark-maybe-sort-alist ()
926 ;;Return the bookmark-alist for display. If the bookmark-sort-flag
927 ;;is non-nil, then return a sorted copy of the alist.
928 (if bookmark-sort-flag
1de49d4e
TTN
929 (sort (copy-alist bookmark-alist)
930 (function
931 (lambda (x y) (string-lessp (car x) (car y)))))
932 bookmark-alist))
d22d6453 933
e3437989 934
866a7257
CD
935(defvar bookmark-after-jump-hook nil
936 "Hook run after `bookmark-jump' jumps to a bookmark.
937Useful for example to unhide text in `outline-mode'.")
938
43f8b275 939(defun bookmark--jump-via (bookmark display-function)
73ba5f6d 940 (bookmark-handle-bookmark bookmark)
43f8b275
SM
941 (save-current-buffer
942 (funcall display-function (current-buffer)))
943 (let ((win (get-buffer-window (current-buffer) 0)))
944 (if win (set-window-point win (point))))
945 ;; FIXME: we used to only run bookmark-after-jump-hook in
946 ;; `bookmark-jump' itself, but in none of the other commands.
947 (run-hooks 'bookmark-after-jump-hook)
948 (if bookmark-automatically-show-annotations
949 ;; if there is an annotation for this bookmark,
950 ;; show it in a buffer.
951 (bookmark-show-annotation bookmark)))
0f219a97 952
43f8b275 953
d22d6453 954;;;###autoload
4eadcdf8 955(defun bookmark-jump (bookmark)
dbe99ae9 956 "Jump to bookmark BOOKMARK (a point in some file).
9aef3b21
RS
957You may have a problem using this function if the value of variable
958`bookmark-alist' is nil. If that happens, you need to load in some
959bookmarks. See help on function `bookmark-load' for more about
d22d6453
RS
960this.
961
e3437989 962If the file pointed to by BOOKMARK no longer exists, you will be asked
d32ff76a 963if you wish to give the bookmark a new location, and `bookmark-jump'
e3437989
RS
964will then jump to the new location, as well as recording it in place
965of the old one in the permanent bookmark record."
966 (interactive
175d0960
SM
967 (list (bookmark-completing-read "Jump to bookmark"
968 bookmark-current-bookmark)))
5d8d3a34
RS
969 (unless bookmark
970 (error "No bookmark specified"))
4eadcdf8 971 (bookmark-maybe-historicize-string bookmark)
43f8b275 972 (bookmark--jump-via bookmark 'switch-to-buffer))
e3437989 973
d22d6453 974
241ab2b5
KF
975;;;###autoload
976(defun bookmark-jump-other-window (bookmark)
977 "Jump to BOOKMARK (a point in some file) in another window.
978See `bookmark-jump'."
979 (interactive
980 (let ((bkm (bookmark-completing-read "Jump to bookmark (in another window)"
981 bookmark-current-bookmark)))
982 (if (> emacs-major-version 21)
983 (list bkm) bkm)))
984 (when bookmark
985 (bookmark-maybe-historicize-string bookmark)
43f8b275 986 (bookmark--jump-via bookmark 'switch-to-buffer-other-window)))
241ab2b5
KF
987
988
8d56596c 989(defun bookmark-file-or-variation-thereof (file)
76bc6ee3
KF
990 "Return FILE (a string) if it exists, or return a reasonable
991variation of FILE if that exists. Reasonable variations are checked
992by appending suffixes defined in `Info-suffix-list'. If cannot find FILE
993nor a reasonable variation thereof, then still return FILE if it can
994be retrieved from a VC backend, else return nil."
dd33e6e9
KF
995 (if (file-exists-p file)
996 file
76bc6ee3
KF
997 (or
998 (progn (require 'info) ; ensure Info-suffix-list is bound
999 (catch 'found
1000 (mapc (lambda (elt)
1001 (let ((suffixed-file (concat file (car elt))))
1002 (if (file-exists-p suffixed-file)
1003 (throw 'found suffixed-file))))
1004 Info-suffix-list)
1005 nil))
1006 ;; Last possibility: try VC
1007 (if (vc-backend file) file))))
1008
79363d93 1009(defun bookmark-jump-noselect (bookmark)
73ba5f6d 1010 "Return the location pointed to by the bookmark BOOKMARK.
8f7028a8
KF
1011The return value has the form (BUFFER . POINT).
1012
1013Note: this function is deprecated and is present for Emacs 22
0f219a97 1014compatibility only."
73ba5f6d
CY
1015 (save-excursion
1016 (bookmark-handle-bookmark bookmark)
1017 (cons (current-buffer) (point))))
1018
0f219a97
JB
1019(make-obsolete 'bookmark-jump-noselect 'bookmark-handle-bookmark "23.1")
1020
73ba5f6d 1021(defun bookmark-handle-bookmark (bookmark)
43f8b275
SM
1022 "Call BOOKMARK's handler or `bookmark-default-handler' if it has none.
1023Changes current buffer and point and returns nil, or signals a `file-error'.
1024BOOKMARK can be a bookmark record used internally by some other
1025elisp package, or the name of a bookmark to be found in `bookmark-alist'."
1026 (condition-case err
1027 (funcall (or (bookmark-get-handler bookmark)
1028 'bookmark-default-handler)
1029 (bookmark-get-bookmark bookmark))
1030 (file-error
1031 ;; We were unable to find the marked file, so ask if user wants to
1032 ;; relocate the bookmark, else remind them to consider deletion.
1033 (when (stringp bookmark)
1034 ;; `bookmark' can either be a bookmark name (found in
1035 ;; `bookmark-alist') or a bookmark object. If it's an object, we
1036 ;; assume it's a bookmark used internally by some other package.
1037 (let ((file (bookmark-get-filename bookmark)))
1038 (when file ;Don't know how to relocate if there's no `file'.
1039 (setq file (expand-file-name file))
1040 (ding)
1041 (if (y-or-n-p (concat (file-name-nondirectory file)
1042 " nonexistent. Relocate \""
1043 bookmark
1044 "\"? "))
1045 (progn
1046 (bookmark-relocate bookmark)
1047 ;; Try again.
1048 (funcall (or (bookmark-get-handler bookmark)
1049 'bookmark-default-handler)
1050 (bookmark-get-bookmark bookmark)))
1051 (message
1052 "Bookmark not relocated; consider removing it \(%s\)." bookmark)
1053 (signal (car err) (cdr err))))))))
1054 ;; Added by db.
1055 (when (stringp bookmark)
1056 (setq bookmark-current-bookmark bookmark))
1057 nil)
1058
1059(defun bookmark-default-handler (bmk)
1060 "Default handler to jump to a particular bookmark location.
1061BMK is a bookmark record.
1062Changes current buffer and point and returns nil, or signals a `file-error'."
1063 (let* ((file (bookmark-get-filename bmk))
1064 (buf (bookmark-prop-get bmk 'buffer))
1065 (forward-str (bookmark-get-front-context-string bmk))
1066 (behind-str (bookmark-get-rear-context-string bmk))
1067 (place (bookmark-get-position bmk)))
79363d93
SM
1068 ;; FIXME: bookmark-file-or-variation-thereof was needed for Info files,
1069 ;; but now that Info bookmarks are handled elsewhere it seems that we
1070 ;; should be able to get rid of it. --Stef
43f8b275
SM
1071 (if (not (if buf (buffer-live-p buf)
1072 (setq file (bookmark-file-or-variation-thereof file))))
1073 (signal 'file-error
1074 `("Jumping to bookmark" "No such file or directory"
1075 (bookmark-get-filename bmk)))
1076 (set-buffer (or buf (find-file-noselect file)))
1077 (if place (goto-char place))
1078
1079 ;; Go searching forward first. Then, if forward-str exists and
1080 ;; was found in the file, we can search backward for behind-str.
1081 ;; Rationale is that if text was inserted between the two in the
1082 ;; file, it's better to be put before it so you can read it,
1083 ;; rather than after and remain perhaps unaware of the changes.
1084 (if forward-str
1085 (if (search-forward forward-str (point-max) t)
1086 (goto-char (match-beginning 0))))
1087 (if behind-str
1088 (if (search-backward behind-str (point-min) t)
1089 (goto-char (match-end 0)))))
1090 nil))
d22d6453
RS
1091
1092;;;###autoload
4eadcdf8 1093(defun bookmark-relocate (bookmark)
5e0e5feb
RS
1094 "Relocate BOOKMARK to another file (reading file name with minibuffer).
1095This makes an already existing bookmark point to that file, instead of
1096the one it used to point at. Useful when a file has been renamed
1097after a bookmark was set in it."
175d0960 1098 (interactive (list (bookmark-completing-read "Bookmark to relocate")))
4eadcdf8 1099 (bookmark-maybe-historicize-string bookmark)
e3437989 1100 (bookmark-maybe-load-default-file)
4eadcdf8 1101 (let* ((bmrk-filename (bookmark-get-filename bookmark))
d22d6453 1102 (newloc (expand-file-name
e3437989 1103 (read-file-name
4eadcdf8 1104 (format "Relocate %s to: " bookmark)
e3437989 1105 (file-name-directory bmrk-filename)))))
91169ba7 1106 (bookmark-set-filename bookmark newloc)
43f8b275
SM
1107 (setq bookmark-alist-modification-count
1108 (1+ bookmark-alist-modification-count))
1109 (if (bookmark-time-to-save-p)
1110 (bookmark-save))
91169ba7 1111 (bookmark-bmenu-surreptitiously-rebuild-list)))
e3437989 1112
d22d6453
RS
1113
1114;;;###autoload
4eadcdf8 1115(defun bookmark-insert-location (bookmark &optional no-history)
4c0b5ad1
KF
1116 "Insert the name of the file associated with BOOKMARK.
1117Optional second arg NO-HISTORY means don't record this in the
1118minibuffer history list `bookmark-history'."
175d0960 1119 (interactive (list (bookmark-completing-read "Insert bookmark location")))
4eadcdf8 1120 (or no-history (bookmark-maybe-historicize-string bookmark))
7e510a5e
RS
1121 (let ((start (point)))
1122 (prog1
1123 (insert (bookmark-location bookmark)) ; *Return this line*
59cfe8b9 1124 (if (and (display-color-p) (display-mouse-p))
8b1b6461
RF
1125 (add-text-properties
1126 start
1127 (save-excursion (re-search-backward
1128 "[^ \t]")
2fbb6576 1129 (1+ (point)))
8b1b6461
RF
1130 '(mouse-face highlight
1131 follow-link t
1132 help-echo "mouse-2: go to this bookmark in other window"))))))
e3437989 1133
fbd98d61 1134;;;###autoload
a15269c0 1135(defalias 'bookmark-locate 'bookmark-insert-location)
e3437989 1136
4eadcdf8 1137(defun bookmark-location (bookmark)
e3437989
RS
1138 "Return the name of the file associated with BOOKMARK."
1139 (bookmark-maybe-load-default-file)
4eadcdf8 1140 (bookmark-get-filename bookmark))
e3437989 1141
d22d6453
RS
1142
1143;;;###autoload
9aef3b21 1144(defun bookmark-rename (old &optional new)
5e0e5feb
RS
1145 "Change the name of OLD bookmark to NEW name.
1146If called from keyboard, prompt for OLD and NEW. If called from
1147menubar, select OLD from a menu and prompt for NEW.
4eadcdf8 1148
5e0e5feb 1149If called from Lisp, prompt for NEW if only OLD was passed as an
4eadcdf8
RS
1150argument. If called with two strings, then no prompting is done. You
1151must pass at least OLD when calling from Lisp.
9aef3b21
RS
1152
1153While you are entering the new name, consecutive C-w's insert
3b526bae 1154consecutive words from the text of the buffer into the new bookmark
4c0b5ad1 1155name."
175d0960 1156 (interactive (list (bookmark-completing-read "Old bookmark name")))
4c0b5ad1 1157 (bookmark-maybe-historicize-string old)
e3437989 1158 (bookmark-maybe-load-default-file)
91169ba7
RS
1159
1160 (setq bookmark-current-point (point))
1161 (setq bookmark-yank-point (point))
1162 (setq bookmark-current-buffer (current-buffer))
1163 (let ((newname
1164 (or new ; use second arg, if non-nil
1165 (read-from-minibuffer
1166 "New name: "
1167 nil
1168 (let ((now-map (copy-keymap minibuffer-local-map)))
1169 (define-key now-map "\C-w" 'bookmark-yank-word)
1170 now-map)
1171 nil
1172 'bookmark-history))))
1173 (bookmark-set-name old newname)
1174 (setq bookmark-current-bookmark newname)
1175 (bookmark-bmenu-surreptitiously-rebuild-list)
1176 (setq bookmark-alist-modification-count
1177 (1+ bookmark-alist-modification-count))
1178 (if (bookmark-time-to-save-p)
1179 (bookmark-save))))
b3bf02fa 1180
e3437989 1181
d22d6453 1182;;;###autoload
4eadcdf8 1183(defun bookmark-insert (bookmark)
dbe99ae9 1184 "Insert the text of the file pointed to by bookmark BOOKMARK.
9aef3b21
RS
1185You may have a problem using this function if the value of variable
1186`bookmark-alist' is nil. If that happens, you need to load in some
1187bookmarks. See help on function `bookmark-load' for more about
8027e2ad 1188this."
175d0960 1189 (interactive (list (bookmark-completing-read "Insert bookmark contents")))
4eadcdf8 1190 (bookmark-maybe-historicize-string bookmark)
e3437989 1191 (bookmark-maybe-load-default-file)
d22d6453 1192 (let ((orig-point (point))
1666a6b3 1193 (str-to-insert
43f8b275 1194 (save-current-buffer
73ba5f6d 1195 (bookmark-handle-bookmark bookmark)
1666a6b3 1196 (buffer-string))))
d22d6453
RS
1197 (insert str-to-insert)
1198 (push-mark)
1199 (goto-char orig-point)))
1200
e3437989 1201
d22d6453 1202;;;###autoload
e3437989 1203(defun bookmark-delete (bookmark &optional batch)
dbe99ae9 1204 "Delete BOOKMARK from the bookmark list.
9aef3b21
RS
1205Removes only the first instance of a bookmark with that name. If
1206there are one or more other bookmarks with the same name, they will
1207not be deleted. Defaults to the \"current\" bookmark \(that is, the
e3437989
RS
1208one most recently used in this file, if any\).
1209Optional second arg BATCH means don't update the bookmark list buffer,
1210probably because we were called from there."
1211 (interactive
175d0960
SM
1212 (list (bookmark-completing-read "Delete bookmark"
1213 bookmark-current-bookmark)))
4c0b5ad1 1214 (bookmark-maybe-historicize-string bookmark)
e3437989 1215 (bookmark-maybe-load-default-file)
2ef435bf 1216 (let ((will-go (bookmark-get-bookmark bookmark 'noerror)))
11eb4275
RS
1217 (setq bookmark-alist (delq will-go bookmark-alist))
1218 ;; Added by db, nil bookmark-current-bookmark if the last
3b526bae 1219 ;; occurrence has been deleted
2ef435bf 1220 (or (bookmark-get-bookmark bookmark-current-bookmark 'noerror)
11eb4275 1221 (setq bookmark-current-bookmark nil)))
e3437989
RS
1222 ;; Don't rebuild the list
1223 (if batch
1224 nil
1225 (bookmark-bmenu-surreptitiously-rebuild-list)
1226 (setq bookmark-alist-modification-count
1227 (1+ bookmark-alist-modification-count))
1228 (if (bookmark-time-to-save-p)
1229 (bookmark-save))))
1230
b3bf02fa
RS
1231
1232(defun bookmark-time-to-save-p (&optional last-time)
1233 ;; By Gregory M. Saunders <saunders@cis.ohio-state.edu>
1234 ;; finds out whether it's time to save bookmarks to a file, by
1235 ;; examining the value of variable bookmark-save-flag, and maybe
1236 ;; bookmark-alist-modification-count. Returns t if they should be
1237 ;; saved, nil otherwise. if last-time is non-nil, then this is
1238 ;; being called when emacs is killed.
dbe99ae9 1239 (cond (last-time
b3bf02fa
RS
1240 (and (> bookmark-alist-modification-count 0)
1241 bookmark-save-flag))
1242 ((numberp bookmark-save-flag)
1243 (>= bookmark-alist-modification-count bookmark-save-flag))
1244 (t
1245 nil)))
1246
e3437989 1247
d22d6453 1248;;;###autoload
b3bf02fa 1249(defun bookmark-write ()
5e0e5feb
RS
1250 "Write bookmarks to a file (reading the file name with the minibuffer).
1251Don't use this in Lisp programs; use `bookmark-save' instead."
b3bf02fa 1252 (interactive)
e3437989 1253 (bookmark-maybe-load-default-file)
b3bf02fa
RS
1254 (bookmark-save t))
1255
e3437989 1256
d22d6453 1257;;;###autoload
dbe99ae9 1258(defun bookmark-save (&optional parg file)
9aef3b21
RS
1259 "Save currently defined bookmarks.
1260Saves by default in the file defined by the variable
4eadcdf8
RS
1261`bookmark-default-file'. With a prefix arg, save it in file FILE
1262\(second argument\).
b3bf02fa 1263
d32ff76a
JB
1264If you are calling this from Lisp, the two arguments are PARG and
1265FILE, and if you just want it to write to the default file, then
b3bf02fa
RS
1266pass no arguments. Or pass in nil and FILE, and it will save in FILE
1267instead. If you pass in one argument, and it is non-nil, then the
1268user will be interactively queried for a file to save in.
1269
11eb4275 1270When you want to load in the bookmarks from a file, use
9aef3b21 1271\`bookmark-load\', \\[bookmark-load]. That function will prompt you
11eb4275 1272for a file, defaulting to the file defined by variable
e3437989 1273`bookmark-default-file'."
b3bf02fa 1274 (interactive "P")
e3437989 1275 (bookmark-maybe-load-default-file)
b3bf02fa
RS
1276 (cond
1277 ((and (null parg) (null file))
1278 ;;whether interactive or not, write to default file
e3437989 1279 (bookmark-write-file bookmark-default-file))
b3bf02fa
RS
1280 ((and (null parg) file)
1281 ;;whether interactive or not, write to given file
1282 (bookmark-write-file file))
1283 ((and parg (not file))
1284 ;;have been called interactively w/ prefix arg
1285 (let ((file (read-file-name "File to save bookmarks in: ")))
1286 (bookmark-write-file file)))
1287 (t ; someone called us with prefix-arg *and* a file, so just write to file
1288 (bookmark-write-file file)))
1289 ;; signal that we have synced the bookmark file by setting this to
1290 ;; 0. If there was an error at any point before, it will not get
1291 ;; set, which is what we want.
1292 (setq bookmark-alist-modification-count 0))
1293
e3437989
RS
1294
1295\f
b3bf02fa 1296(defun bookmark-write-file (file)
43f8b275
SM
1297 (bookmark-maybe-message "Saving bookmarks to file %s..." file)
1298 (with-current-buffer (get-buffer-create " *Bookmarks*")
1299 (goto-char (point-min))
1300 (delete-region (point-min) (point-max))
1301 (let ((print-length nil)
1302 (print-level nil))
1303 (bookmark-insert-file-format-version-stamp)
1304 (pp bookmark-alist (current-buffer))
1305 (let ((version-control
1306 (cond
1307 ((null bookmark-version-control) nil)
1308 ((eq 'never bookmark-version-control) 'never)
1309 ((eq 'nospecial bookmark-version-control) version-control)
1310 (t t))))
1311 (condition-case nil
1312 (write-region (point-min) (point-max) file)
1313 (file-error (message "Can't write %s" file)))
1314 (kill-buffer (current-buffer))
1315 (bookmark-maybe-message
1316 "Saving bookmarks to file %s...done" file)))))
e3437989 1317
d22d6453 1318
91169ba7
RS
1319(defun bookmark-import-new-list (new-list)
1320 ;; Walk over the new list, adding each individual bookmark
1321 ;; carefully. "Carefully" means checking against the existing
1322 ;; bookmark-alist and renaming the new bookmarks with <N> extensions
1323 ;; as necessary.
1324 (let ((lst new-list)
1325 (names (bookmark-all-names)))
1326 (while lst
1327 (let* ((full-record (car lst)))
1328 (bookmark-maybe-rename full-record names)
1329 (setq bookmark-alist (nconc bookmark-alist (list full-record)))
1330 (setq names (cons (bookmark-name-from-full-record full-record) names))
1331 (setq lst (cdr lst))))))
1332
1333
1334(defun bookmark-maybe-rename (full-record names)
1335 ;; just a helper for bookmark-import-new-list; it is only for
1336 ;; readability that this is not inlined.
1337 ;;
1338 ;; Once this has found a free name, it sets full-record to that
1339 ;; name.
1340 (let ((found-name (bookmark-name-from-full-record full-record)))
1341 (if (member found-name names)
1342 ;; We've got a conflict, so generate a new name
1343 (let ((count 2)
1344 (new-name found-name))
1345 (while (member new-name names)
1346 (setq new-name (concat found-name (format "<%d>" count)))
1347 (setq count (1+ count)))
1348 (bookmark-set-name full-record new-name)))))
1349
1350
d22d6453 1351;;;###autoload
91169ba7 1352(defun bookmark-load (file &optional overwrite no-msg)
9aef3b21
RS
1353 "Load bookmarks from FILE (which must be in bookmark format).
1354Appends loaded bookmarks to the front of the list of bookmarks. If
91169ba7 1355optional second argument OVERWRITE is non-nil, existing bookmarks are
9aef3b21
RS
1356destroyed. Optional third arg NO-MSG means don't display any messages
1357while loading.
b3bf02fa
RS
1358
1359If you load a file that doesn't contain a proper bookmark alist, you
9aef3b21 1360will corrupt Emacs's bookmark list. Generally, you should only load
b3bf02fa 1361in files that were created with the bookmark functions in the first
e3437989 1362place. Your own personal bookmark file, `~/.emacs.bmk', is
8027e2ad 1363maintained automatically by Emacs; you shouldn't need to load it
91169ba7
RS
1364explicitly.
1365
1366If you load a file containing bookmarks with the same names as
1367bookmarks already present in your Emacs, the new bookmarks will get
1368unique numeric suffixes \"<2>\", \"<3>\", ... following the same
1369method buffers use to resolve name collisions."
b3bf02fa 1370 (interactive
e3437989
RS
1371 (list (read-file-name
1372 (format "Load bookmarks from: (%s) "
dbe99ae9 1373 bookmark-default-file)
e3437989
RS
1374 ;;Default might not be used often,
1375 ;;but there's no better default, and
1376 ;;I guess it's better than none at all.
1377 "~/" bookmark-default-file 'confirm)))
b3bf02fa 1378 (setq file (expand-file-name file))
43f8b275
SM
1379 (if (not (file-readable-p file))
1380 (error "Cannot read bookmark file %s" file)
1381 (if (null no-msg)
1382 (bookmark-maybe-message "Loading bookmarks from %s..." file))
1383 (with-current-buffer (let ((enable-local-variables nil))
1384 (find-file-noselect file))
1385 (goto-char (point-min))
1386 (bookmark-maybe-upgrade-file-format)
1387 (let ((blist (bookmark-alist-from-buffer)))
1388 (if (listp blist)
1389 (progn
1390 (if overwrite
1391 (progn
1392 (setq bookmark-alist blist)
1393 (setq bookmark-alist-modification-count 0))
1394 ;; else
1395 (bookmark-import-new-list blist)
1396 (setq bookmark-alist-modification-count
1397 (1+ bookmark-alist-modification-count)))
1398 (if (string-equal
1399 (expand-file-name bookmark-default-file)
1400 file)
1401 (setq bookmarks-already-loaded t))
1402 (bookmark-bmenu-surreptitiously-rebuild-list))
1403 (error "Invalid bookmark list in %s" file)))
1404 (kill-buffer (current-buffer)))
1405 (if (null no-msg)
1406 (bookmark-maybe-message "Loading bookmarks from %s...done" file))))
b3bf02fa 1407
d22d6453 1408
e3437989 1409\f
43f8b275
SM
1410;;; Code supporting the dired-like bookmark menu.
1411;; Prefix is "bookmark-bmenu" for "buffer-menu":
e3437989
RS
1412
1413
1414(defvar bookmark-bmenu-bookmark-column nil)
d22d6453 1415
d22d6453 1416
e3437989
RS
1417(defvar bookmark-bmenu-hidden-bookmarks ())
1418
1419
e3437989 1420(defvar bookmark-bmenu-mode-map nil)
d22d6453 1421
d22d6453 1422
e3437989 1423(if bookmark-bmenu-mode-map
d22d6453 1424 nil
e3437989
RS
1425 (setq bookmark-bmenu-mode-map (make-keymap))
1426 (suppress-keymap bookmark-bmenu-mode-map t)
31cd9611 1427 (define-key bookmark-bmenu-mode-map "q" 'quit-window)
e3437989
RS
1428 (define-key bookmark-bmenu-mode-map "v" 'bookmark-bmenu-select)
1429 (define-key bookmark-bmenu-mode-map "w" 'bookmark-bmenu-locate)
1430 (define-key bookmark-bmenu-mode-map "2" 'bookmark-bmenu-2-window)
1431 (define-key bookmark-bmenu-mode-map "1" 'bookmark-bmenu-1-window)
1432 (define-key bookmark-bmenu-mode-map "j" 'bookmark-bmenu-this-window)
fbd98d61 1433 (define-key bookmark-bmenu-mode-map "\C-c\C-c" 'bookmark-bmenu-this-window)
e3437989 1434 (define-key bookmark-bmenu-mode-map "f" 'bookmark-bmenu-this-window)
74002bdf 1435 (define-key bookmark-bmenu-mode-map "\C-m" 'bookmark-bmenu-this-window)
e3437989 1436 (define-key bookmark-bmenu-mode-map "o" 'bookmark-bmenu-other-window)
fbd98d61
KF
1437 (define-key bookmark-bmenu-mode-map "\C-o"
1438 'bookmark-bmenu-switch-other-window)
e3437989
RS
1439 (define-key bookmark-bmenu-mode-map "s" 'bookmark-bmenu-save)
1440 (define-key bookmark-bmenu-mode-map "k" 'bookmark-bmenu-delete)
1441 (define-key bookmark-bmenu-mode-map "\C-d" 'bookmark-bmenu-delete-backwards)
1442 (define-key bookmark-bmenu-mode-map "x" 'bookmark-bmenu-execute-deletions)
e3437989
RS
1443 (define-key bookmark-bmenu-mode-map "d" 'bookmark-bmenu-delete)
1444 (define-key bookmark-bmenu-mode-map " " 'next-line)
1445 (define-key bookmark-bmenu-mode-map "n" 'next-line)
1446 (define-key bookmark-bmenu-mode-map "p" 'previous-line)
1447 (define-key bookmark-bmenu-mode-map "\177" 'bookmark-bmenu-backup-unmark)
1448 (define-key bookmark-bmenu-mode-map "?" 'describe-mode)
1449 (define-key bookmark-bmenu-mode-map "u" 'bookmark-bmenu-unmark)
1450 (define-key bookmark-bmenu-mode-map "m" 'bookmark-bmenu-mark)
dbe99ae9 1451 (define-key bookmark-bmenu-mode-map "l" 'bookmark-bmenu-load)
e3437989 1452 (define-key bookmark-bmenu-mode-map "r" 'bookmark-bmenu-rename)
037b0a87 1453 (define-key bookmark-bmenu-mode-map "R" 'bookmark-bmenu-relocate)
e3437989
RS
1454 (define-key bookmark-bmenu-mode-map "t" 'bookmark-bmenu-toggle-filenames)
1455 (define-key bookmark-bmenu-mode-map "a" 'bookmark-bmenu-show-annotation)
1456 (define-key bookmark-bmenu-mode-map "A" 'bookmark-bmenu-show-all-annotations)
7e510a5e
RS
1457 (define-key bookmark-bmenu-mode-map "e" 'bookmark-bmenu-edit-annotation)
1458 (define-key bookmark-bmenu-mode-map [mouse-2]
1459 'bookmark-bmenu-other-window-with-mouse))
e3437989 1460
dbe99ae9 1461
e3437989
RS
1462
1463;; Bookmark Buffer Menu mode is suitable only for specially formatted
1464;; data.
1465(put 'bookmark-bmenu-mode 'mode-class 'special)
1466
1467
1468;; todo: need to display whether or not bookmark exists as a buffer in
dbe99ae9 1469;; flag column.
d22d6453
RS
1470
1471;; Format:
e3437989
RS
1472;; FLAGS BOOKMARK [ LOCATION ]
1473
1474
1475(defun bookmark-bmenu-surreptitiously-rebuild-list ()
1476 "Rebuild the Bookmark List if it exists.
1477Don't affect the buffer ring order."
1478 (if (get-buffer "*Bookmark List*")
1479 (save-excursion
dbe99ae9 1480 (save-window-excursion
e3437989 1481 (bookmark-bmenu-list)))))
d22d6453 1482
d22d6453
RS
1483
1484;;;###autoload
e3437989 1485(defun bookmark-bmenu-list ()
d22d6453
RS
1486 "Display a list of existing bookmarks.
1487The list is displayed in a buffer named `*Bookmark List*'.
e3437989
RS
1488The leftmost column displays a D if the bookmark is flagged for
1489deletion, or > if it is flagged for displaying."
d22d6453 1490 (interactive)
e3437989
RS
1491 (bookmark-maybe-load-default-file)
1492 (if (interactive-p)
1493 (switch-to-buffer (get-buffer-create "*Bookmark List*"))
1494 (set-buffer (get-buffer-create "*Bookmark List*")))
175d0960
SM
1495 (let ((inhibit-read-only t))
1496 (erase-buffer)
d22d6453 1497 (insert "% Bookmark\n- --------\n")
37789292
RF
1498 (add-text-properties (point-min) (point)
1499 '(font-lock-face bookmark-menu-heading))
76865665 1500 (mapc
e3437989 1501 (lambda (full-record)
3b526bae 1502 ;; if a bookmark has an annotation, prepend a "*"
e3437989
RS
1503 ;; in the list of bookmarks.
1504 (let ((annotation (bookmark-get-annotation
1505 (bookmark-name-from-full-record full-record))))
91169ba7 1506 (if (and annotation (not (string-equal annotation "")))
e3437989
RS
1507 (insert " *")
1508 (insert " "))
7e510a5e
RS
1509 (let ((start (point)))
1510 (insert (bookmark-name-from-full-record full-record))
59cfe8b9 1511 (if (and (display-color-p) (display-mouse-p))
8b1b6461
RF
1512 (add-text-properties
1513 start
1514 (save-excursion (re-search-backward
1515 "[^ \t]")
1516 (1+ (point)))
1517 '(mouse-face highlight
1518 follow-link t
1519 help-echo "mouse-2: go to this bookmark in other window")))
7e510a5e
RS
1520 (insert "\n")
1521 )))
1de49d4e 1522 (bookmark-maybe-sort-alist)))
d22d6453
RS
1523 (goto-char (point-min))
1524 (forward-line 2)
e3437989
RS
1525 (bookmark-bmenu-mode)
1526 (if bookmark-bmenu-toggle-filenames
1527 (bookmark-bmenu-toggle-filenames t)))
1528
1529;;;###autoload
1530(defalias 'list-bookmarks 'bookmark-bmenu-list)
1531;;;###autoload
1532(defalias 'edit-bookmarks 'bookmark-bmenu-list)
d22d6453 1533
e3437989
RS
1534
1535
1536(defun bookmark-bmenu-mode ()
d22d6453
RS
1537 "Major mode for editing a list of bookmarks.
1538Each line describes one of the bookmarks in Emacs.
1539Letters do not insert themselves; instead, they are commands.
3b526bae 1540Bookmark names preceded by a \"*\" have annotations.
e3437989
RS
1541\\<bookmark-bmenu-mode-map>
1542\\[bookmark-bmenu-mark] -- mark bookmark to be displayed.
1543\\[bookmark-bmenu-select] -- select bookmark of line point is on.
1544 Also show bookmarks marked using m in other windows.
1545\\[bookmark-bmenu-toggle-filenames] -- toggle displaying of filenames (they may obscure long bookmark names).
1546\\[bookmark-bmenu-locate] -- display (in minibuffer) location of this bookmark.
1547\\[bookmark-bmenu-1-window] -- select this bookmark in full-frame window.
1548\\[bookmark-bmenu-2-window] -- select this bookmark in one window,
d22d6453 1549 together with bookmark selected before this one in another window.
e3437989
RS
1550\\[bookmark-bmenu-this-window] -- select this bookmark in place of the bookmark menu buffer.
1551\\[bookmark-bmenu-other-window] -- select this bookmark in another window,
d22d6453 1552 so the bookmark menu bookmark remains visible in its window.
e3437989 1553\\[bookmark-bmenu-switch-other-window] -- switch the other window to this bookmark.
dbe99ae9 1554\\[bookmark-bmenu-rename] -- rename this bookmark \(prompts for new name\).
037b0a87 1555\\[bookmark-bmenu-relocate] -- relocate this bookmark's file \(prompts for new file\).
e3437989 1556\\[bookmark-bmenu-delete] -- mark this bookmark to be deleted, and move down.
dbe99ae9 1557\\[bookmark-bmenu-delete-backwards] -- mark this bookmark to be deleted, and move up.
60d0378e 1558\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[bookmark-bmenu-delete]'.
e3437989 1559\\[bookmark-bmenu-save] -- save the current bookmark list in the default file.
d22d6453 1560 With a prefix arg, prompts for a file to save in.
e3437989
RS
1561\\[bookmark-bmenu-load] -- load in a file of bookmarks (prompts for file.)
1562\\[bookmark-bmenu-unmark] -- remove all kinds of marks from current line.
d22d6453 1563 With prefix argument, also move up one line.
e3437989
RS
1564\\[bookmark-bmenu-backup-unmark] -- back up a line and remove marks.
1565\\[bookmark-bmenu-show-annotation] -- show the annotation, if it exists, for the current bookmark
1566 in another buffer.
1567\\[bookmark-bmenu-show-all-annotations] -- show the annotations of all bookmarks in another buffer.
1568\\[bookmark-bmenu-edit-annotation] -- edit the annotation for the current bookmark."
d22d6453 1569 (kill-all-local-variables)
e3437989 1570 (use-local-map bookmark-bmenu-mode-map)
d22d6453
RS
1571 (setq truncate-lines t)
1572 (setq buffer-read-only t)
e3437989 1573 (setq major-mode 'bookmark-bmenu-mode)
d22d6453 1574 (setq mode-name "Bookmark Menu")
f33cee85 1575 (run-mode-hooks 'bookmark-bmenu-mode-hook))
d22d6453 1576
e3437989 1577
4eadcdf8 1578(defun bookmark-bmenu-toggle-filenames (&optional show)
d22d6453
RS
1579 "Toggle whether filenames are shown in the bookmark list.
1580Optional argument SHOW means show them unconditionally."
1581 (interactive)
1582 (cond
4eadcdf8 1583 (show
e3437989
RS
1584 (setq bookmark-bmenu-toggle-filenames nil)
1585 (bookmark-bmenu-show-filenames)
1586 (setq bookmark-bmenu-toggle-filenames t))
1587 (bookmark-bmenu-toggle-filenames
1588 (bookmark-bmenu-hide-filenames)
1589 (setq bookmark-bmenu-toggle-filenames nil))
d22d6453 1590 (t
e3437989
RS
1591 (bookmark-bmenu-show-filenames)
1592 (setq bookmark-bmenu-toggle-filenames t))))
1593
d22d6453 1594
e3437989
RS
1595(defun bookmark-bmenu-show-filenames (&optional force)
1596 (if (and (not force) bookmark-bmenu-toggle-filenames)
d22d6453
RS
1597 nil ;already shown, so do nothing
1598 (save-excursion
1599 (save-window-excursion
1600 (goto-char (point-min))
1601 (forward-line 2)
e3437989 1602 (setq bookmark-bmenu-hidden-bookmarks ())
175d0960 1603 (let ((inhibit-read-only t))
d22d6453 1604 (while (< (point) (point-max))
e3437989
RS
1605 (let ((bmrk (bookmark-bmenu-bookmark)))
1606 (setq bookmark-bmenu-hidden-bookmarks
1607 (cons bmrk bookmark-bmenu-hidden-bookmarks))
7e510a5e
RS
1608 (let ((start (save-excursion (end-of-line) (point))))
1609 (move-to-column bookmark-bmenu-file-column t)
1610 ;; Strip off `mouse-face' from the white spaces region.
59cfe8b9 1611 (if (and (display-color-p) (display-mouse-p))
7e510a5e 1612 (remove-text-properties start (point)
2fbb6576 1613 '(mouse-face nil help-echo nil))))
7e510a5e 1614 (delete-region (point) (progn (end-of-line) (point)))
d22d6453 1615 (insert " ")
4c0b5ad1
KF
1616 ;; Pass the NO-HISTORY arg:
1617 (bookmark-insert-location bmrk t)
d22d6453
RS
1618 (forward-line 1))))))))
1619
e3437989
RS
1620
1621(defun bookmark-bmenu-hide-filenames (&optional force)
1622 (if (and (not force) bookmark-bmenu-toggle-filenames)
d22d6453
RS
1623 ;; nothing to hide if above is nil
1624 (save-excursion
1625 (save-window-excursion
1626 (goto-char (point-min))
1627 (forward-line 2)
e3437989
RS
1628 (setq bookmark-bmenu-hidden-bookmarks
1629 (nreverse bookmark-bmenu-hidden-bookmarks))
d22d6453
RS
1630 (save-excursion
1631 (goto-char (point-min))
1632 (search-forward "Bookmark")
1633 (backward-word 1)
e3437989 1634 (setq bookmark-bmenu-bookmark-column (current-column)))
d22d6453 1635 (save-excursion
175d0960 1636 (let ((inhibit-read-only t))
e3437989
RS
1637 (while bookmark-bmenu-hidden-bookmarks
1638 (move-to-column bookmark-bmenu-bookmark-column t)
1639 (bookmark-kill-line)
7e510a5e
RS
1640 (let ((start (point)))
1641 (insert (car bookmark-bmenu-hidden-bookmarks))
59cfe8b9 1642 (if (and (display-color-p) (display-mouse-p))
8b1b6461
RF
1643 (add-text-properties
1644 start
1645 (save-excursion (re-search-backward
1646 "[^ \t]")
1647 (1+ (point)))
1648 '(mouse-face highlight
1649 follow-link t
1650 help-echo
1651 "mouse-2: go to this bookmark in other window"))))
e3437989
RS
1652 (setq bookmark-bmenu-hidden-bookmarks
1653 (cdr bookmark-bmenu-hidden-bookmarks))
d22d6453
RS
1654 (forward-line 1))))))))
1655
e3437989 1656
e3437989 1657(defun bookmark-bmenu-check-position ()
91169ba7
RS
1658 ;; Returns non-nil if on a line with a bookmark.
1659 ;; (The actual value returned is bookmark-alist).
1660 ;; Else reposition and try again, else return nil.
d22d6453
RS
1661 (cond ((< (count-lines (point-min) (point)) 2)
1662 (goto-char (point-min))
1663 (forward-line 2)
91169ba7 1664 bookmark-alist)
d22d6453
RS
1665 ((and (bolp) (eobp))
1666 (beginning-of-line 0)
91169ba7 1667 bookmark-alist)
d22d6453 1668 (t
91169ba7 1669 bookmark-alist)))
d22d6453 1670
e3437989
RS
1671
1672(defun bookmark-bmenu-bookmark ()
d22d6453 1673 ;; return a string which is bookmark of this line.
e3437989 1674 (if (bookmark-bmenu-check-position)
d22d6453
RS
1675 (save-excursion
1676 (save-window-excursion
1677 (goto-char (point-min))
1678 (search-forward "Bookmark")
1679 (backward-word 1)
e3437989
RS
1680 (setq bookmark-bmenu-bookmark-column (current-column)))))
1681 (if bookmark-bmenu-toggle-filenames
1682 (bookmark-bmenu-hide-filenames))
d22d6453
RS
1683 (save-excursion
1684 (save-window-excursion
1685 (beginning-of-line)
e3437989 1686 (forward-char bookmark-bmenu-bookmark-column)
d22d6453 1687 (prog1
dbe99ae9
SS
1688 (buffer-substring-no-properties (point)
1689 (progn
d22d6453
RS
1690 (end-of-line)
1691 (point)))
1692 ;; well, this is certainly crystal-clear:
e3437989
RS
1693 (if bookmark-bmenu-toggle-filenames
1694 (bookmark-bmenu-toggle-filenames t))))))
d22d6453 1695
e3437989
RS
1696
1697(defun bookmark-show-annotation (bookmark)
1698 "Display the annotation for bookmark named BOOKMARK in a buffer,
1699if an annotation exists."
1700 (let ((annotation (bookmark-get-annotation bookmark)))
91169ba7
RS
1701 (if (and annotation (not (string-equal annotation "")))
1702 (save-excursion
1703 (let ((old-buf (current-buffer)))
1704 (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t)
1705 (delete-region (point-min) (point-max))
1706 ;; (insert (concat "Annotation for bookmark '" bookmark "':\n\n"))
1707 (insert annotation)
1708 (goto-char (point-min))
1709 (pop-to-buffer old-buf))))))
e3437989
RS
1710
1711
1712(defun bookmark-show-all-annotations ()
1713 "Display the annotations for all bookmarks in a buffer."
1714 (let ((old-buf (current-buffer)))
1715 (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t)
1716 (delete-region (point-min) (point-max))
76865665 1717 (mapc
e3437989
RS
1718 (lambda (full-record)
1719 (let* ((name (bookmark-name-from-full-record full-record))
1720 (ann (bookmark-get-annotation name)))
1721 (insert (concat name ":\n"))
91169ba7 1722 (if (and ann (not (string-equal ann "")))
e3437989
RS
1723 ;; insert the annotation, indented by 4 spaces.
1724 (progn
fd5306d2
TTN
1725 (save-excursion (insert ann) (unless (bolp)
1726 (insert "\n")))
e3437989
RS
1727 (while (< (point) (point-max))
1728 (beginning-of-line) ; paranoia
1729 (insert " ")
1730 (forward-line)
1731 (end-of-line))))))
1732 bookmark-alist)
1733 (goto-char (point-min))
1734 (pop-to-buffer old-buf)))
1735
1736
1737(defun bookmark-bmenu-mark ()
5e0e5feb 1738 "Mark bookmark on this line to be displayed by \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-select]."
d22d6453
RS
1739 (interactive)
1740 (beginning-of-line)
e3437989 1741 (if (bookmark-bmenu-check-position)
175d0960 1742 (let ((inhibit-read-only t))
d22d6453
RS
1743 (delete-char 1)
1744 (insert ?>)
91169ba7
RS
1745 (forward-line 1)
1746 (bookmark-bmenu-check-position))))
d22d6453 1747
e3437989
RS
1748
1749(defun bookmark-bmenu-select ()
d22d6453 1750 "Select this line's bookmark; also display bookmarks marked with `>'.
e3437989 1751You can mark bookmarks with the \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-mark] command."
d22d6453 1752 (interactive)
e3437989
RS
1753 (if (bookmark-bmenu-check-position)
1754 (let ((bmrk (bookmark-bmenu-bookmark))
dbe99ae9 1755 (menu (current-buffer))
d22d6453
RS
1756 (others ())
1757 tem)
1758 (goto-char (point-min))
1759 (while (re-search-forward "^>" nil t)
e3437989 1760 (setq tem (bookmark-bmenu-bookmark))
175d0960 1761 (let ((inhibit-read-only t))
d22d6453 1762 (delete-char -1)
d32ff76a 1763 (insert ?\s))
dbe99ae9
SS
1764 (or (string-equal tem bmrk)
1765 (member tem others)
d22d6453
RS
1766 (setq others (cons tem others))))
1767 (setq others (nreverse others)
1768 tem (/ (1- (frame-height)) (1+ (length others))))
1769 (delete-other-windows)
1770 (bookmark-jump bmrk)
1771 (bury-buffer menu)
4eadcdf8
RS
1772 (if others
1773 (while others
1774 (split-window nil tem)
1775 (other-window 1)
1776 (bookmark-jump (car others))
1777 (setq others (cdr others)))
d22d6453
RS
1778 (other-window 1)))))
1779
e3437989
RS
1780
1781(defun bookmark-bmenu-save (parg)
d22d6453
RS
1782 "Save the current list into a bookmark file.
1783With a prefix arg, prompts for a file to save them in."
1784 (interactive "P")
1785 (save-excursion
1786 (save-window-excursion
1787 (bookmark-save parg))))
1788
e3437989
RS
1789
1790(defun bookmark-bmenu-load ()
1791 "Load the bookmark file and rebuild the bookmark menu-buffer."
d22d6453 1792 (interactive)
e3437989 1793 (if (bookmark-bmenu-check-position)
d22d6453
RS
1794 (save-excursion
1795 (save-window-excursion
e3437989 1796 ;; This will call `bookmark-bmenu-list'
d22d6453
RS
1797 (call-interactively 'bookmark-load)))))
1798
e3437989
RS
1799
1800(defun bookmark-bmenu-1-window ()
d22d6453
RS
1801 "Select this line's bookmark, alone, in full frame."
1802 (interactive)
e3437989 1803 (if (bookmark-bmenu-check-position)
d22d6453 1804 (progn
e3437989 1805 (bookmark-jump (bookmark-bmenu-bookmark))
d22d6453
RS
1806 (bury-buffer (other-buffer))
1807 (delete-other-windows))))
1808
e3437989
RS
1809
1810(defun bookmark-bmenu-2-window ()
d22d6453
RS
1811 "Select this line's bookmark, with previous buffer in second window."
1812 (interactive)
e3437989
RS
1813 (if (bookmark-bmenu-check-position)
1814 (let ((bmrk (bookmark-bmenu-bookmark))
d22d6453
RS
1815 (menu (current-buffer))
1816 (pop-up-windows t))
1817 (delete-other-windows)
1818 (switch-to-buffer (other-buffer))
43f8b275
SM
1819 (let ((bookmark-automatically-show-annotations nil)) ;FIXME: needed?
1820 (bookmark--jump-via bmrk 'pop-to-buffer))
d22d6453
RS
1821 (bury-buffer menu))))
1822
e3437989
RS
1823
1824(defun bookmark-bmenu-this-window ()
d22d6453
RS
1825 "Select this line's bookmark in this window."
1826 (interactive)
e3437989
RS
1827 (if (bookmark-bmenu-check-position)
1828 (bookmark-jump (bookmark-bmenu-bookmark))))
d22d6453 1829
e3437989
RS
1830
1831(defun bookmark-bmenu-other-window ()
d22d6453
RS
1832 "Select this line's bookmark in other window, leaving bookmark menu visible."
1833 (interactive)
e3437989
RS
1834 (let ((bookmark (bookmark-bmenu-bookmark)))
1835 (if (bookmark-bmenu-check-position)
43f8b275
SM
1836 (let ((bookmark-automatically-show-annotations t)) ;FIXME: needed?
1837 (bookmark--jump-via bookmark 'switch-to-buffer-other-window)))))
e40e3151
KF
1838
1839
1840(defun bookmark-bmenu-switch-other-window ()
1841 "Make the other window select this line's bookmark.
1842The current window remains selected."
1843 (interactive)
e197b151
RS
1844 (let ((bookmark (bookmark-bmenu-bookmark))
1845 (pop-up-windows t)
dbe99ae9 1846 same-window-buffer-names
e197b151 1847 same-window-regexps)
e40e3151 1848 (if (bookmark-bmenu-check-position)
43f8b275
SM
1849 (let ((bookmark-automatically-show-annotations t)) ;FIXME: needed?
1850 (bookmark--jump-via bookmark 'display-buffer)))))
e3437989 1851
7e510a5e
RS
1852(defun bookmark-bmenu-other-window-with-mouse (event)
1853 "Select bookmark at the mouse pointer in other window, leaving bookmark menu visible."
1854 (interactive "e")
43f8b275 1855 (with-current-buffer (window-buffer (posn-window (event-end event)))
7e510a5e
RS
1856 (save-excursion
1857 (goto-char (posn-point (event-end event)))
1858 (bookmark-bmenu-other-window))))
1859
e3437989
RS
1860
1861(defun bookmark-bmenu-show-annotation ()
1862 "Show the annotation for the current bookmark in another window."
1863 (interactive)
1864 (let ((bookmark (bookmark-bmenu-bookmark)))
1865 (if (bookmark-bmenu-check-position)
1866 (bookmark-show-annotation bookmark))))
d22d6453 1867
e3437989
RS
1868
1869(defun bookmark-bmenu-show-all-annotations ()
1870 "Show the annotation for all bookmarks in another window."
1871 (interactive)
1872 (bookmark-show-all-annotations))
1873
1874
1875(defun bookmark-bmenu-edit-annotation ()
1876 "Edit the annotation for the current bookmark in another window."
1877 (interactive)
1878 (let ((bookmark (bookmark-bmenu-bookmark)))
1879 (if (bookmark-bmenu-check-position)
1880 (bookmark-edit-annotation bookmark))))
1881
1882
e3437989 1883(defun bookmark-bmenu-unmark (&optional backup)
d22d6453 1884 "Cancel all requested operations on bookmark on this line and move down.
4eadcdf8 1885Optional BACKUP means move up."
d22d6453
RS
1886 (interactive "P")
1887 (beginning-of-line)
e3437989 1888 (if (bookmark-bmenu-check-position)
d22d6453 1889 (progn
175d0960 1890 (let ((inhibit-read-only t))
d22d6453
RS
1891 (delete-char 1)
1892 ;; any flags to reset according to circumstances? How about a
1893 ;; flag indicating whether this bookmark is being visited?
1894 ;; well, we don't have this now, so maybe later.
1895 (insert " "))
91169ba7
RS
1896 (forward-line (if backup -1 1))
1897 (bookmark-bmenu-check-position))))
d22d6453 1898
e3437989
RS
1899
1900(defun bookmark-bmenu-backup-unmark ()
d22d6453
RS
1901 "Move up and cancel all requested operations on bookmark on line above."
1902 (interactive)
1903 (forward-line -1)
e3437989 1904 (if (bookmark-bmenu-check-position)
d22d6453 1905 (progn
e3437989 1906 (bookmark-bmenu-unmark)
91169ba7
RS
1907 (forward-line -1)
1908 (bookmark-bmenu-check-position))))
d22d6453 1909
e3437989
RS
1910
1911(defun bookmark-bmenu-delete ()
5e0e5feb
RS
1912 "Mark bookmark on this line to be deleted.
1913To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-execute-deletions]."
d22d6453
RS
1914 (interactive)
1915 (beginning-of-line)
e3437989 1916 (if (bookmark-bmenu-check-position)
175d0960 1917 (let ((inhibit-read-only t))
d22d6453
RS
1918 (delete-char 1)
1919 (insert ?D)
91169ba7
RS
1920 (forward-line 1)
1921 (bookmark-bmenu-check-position))))
d22d6453 1922
e3437989
RS
1923
1924(defun bookmark-bmenu-delete-backwards ()
5e0e5feb
RS
1925 "Mark bookmark on this line to be deleted, then move up one line.
1926To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-execute-deletions]."
d22d6453 1927 (interactive)
e3437989 1928 (bookmark-bmenu-delete)
d22d6453 1929 (forward-line -2)
e3437989 1930 (if (bookmark-bmenu-check-position)
91169ba7
RS
1931 (forward-line 1))
1932 (bookmark-bmenu-check-position))
d22d6453 1933
e3437989
RS
1934
1935(defun bookmark-bmenu-execute-deletions ()
d22d6453
RS
1936 "Delete bookmarks marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
1937 (interactive)
60d0378e 1938 (message "Deleting bookmarks...")
e3437989
RS
1939 (let ((hide-em bookmark-bmenu-toggle-filenames)
1940 (o-point (point))
1941 (o-str (save-excursion
1942 (beginning-of-line)
1943 (if (looking-at "^D")
1944 nil
1945 (buffer-substring
1946 (point)
1947 (progn (end-of-line) (point))))))
1948 (o-col (current-column)))
1949 (if hide-em (bookmark-bmenu-hide-filenames))
1950 (setq bookmark-bmenu-toggle-filenames nil)
d22d6453
RS
1951 (goto-char (point-min))
1952 (forward-line 1)
e3437989
RS
1953 (while (re-search-forward "^D" (point-max) t)
1954 (bookmark-delete (bookmark-bmenu-bookmark) t)) ; pass BATCH arg
1955 (bookmark-bmenu-list)
1956 (setq bookmark-bmenu-toggle-filenames hide-em)
1957 (if bookmark-bmenu-toggle-filenames
1958 (bookmark-bmenu-toggle-filenames t))
1959 (if o-str
1960 (progn
1961 (goto-char (point-min))
1962 (search-forward o-str)
1963 (beginning-of-line)
1964 (forward-char o-col))
1965 (goto-char o-point))
1966 (beginning-of-line)
1967 (setq bookmark-alist-modification-count
1968 (1+ bookmark-alist-modification-count))
1969 (if (bookmark-time-to-save-p)
60d0378e
KF
1970 (bookmark-save))
1971 (message "Deleting bookmarks...done")
1972 ))
e3437989
RS
1973
1974
1975(defun bookmark-bmenu-rename ()
d22d6453
RS
1976 "Rename bookmark on current line. Prompts for a new name."
1977 (interactive)
e3437989
RS
1978 (if (bookmark-bmenu-check-position)
1979 (let ((bmrk (bookmark-bmenu-bookmark))
d22d6453
RS
1980 (thispoint (point)))
1981 (bookmark-rename bmrk)
e3437989 1982 (bookmark-bmenu-list)
d22d6453
RS
1983 (goto-char thispoint))))
1984
e3437989
RS
1985
1986(defun bookmark-bmenu-locate ()
d22d6453
RS
1987 "Display location of this bookmark. Displays in the minibuffer."
1988 (interactive)
e3437989
RS
1989 (if (bookmark-bmenu-check-position)
1990 (let ((bmrk (bookmark-bmenu-bookmark)))
8a26c165 1991 (message "%s" (bookmark-location bmrk)))))
e3437989 1992
037b0a87
KF
1993(defun bookmark-bmenu-relocate ()
1994 "Change the file path of the bookmark on the current line,
1995 prompting with completion for the new path."
1996 (interactive)
1997 (if (bookmark-bmenu-check-position)
1998 (let ((bmrk (bookmark-bmenu-bookmark))
1999 (thispoint (point)))
2000 (bookmark-relocate bmrk)
2001 (goto-char thispoint))))
d22d6453 2002
e3437989
RS
2003\f
2004;;; Menu bar stuff. Prefix is "bookmark-menu".
11eb4275 2005
e3437989
RS
2006(defun bookmark-menu-popup-paned-menu (event name entries)
2007 "Pop up multi-paned menu at EVENT, return string chosen from ENTRIES.
2008That is, ENTRIES is a list of strings which appear as the choices
2009in the menu.
175d0960
SM
2010The number of panes depends on the number of entries.
2011The visible entries are truncated to `bookmark-menu-length', but the
2012strings returned are not."
2013 (let ((f-height (/ (frame-height) 2))
2014 (pane-list nil)
2015 (iter 0))
2016 (while entries
2017 (let (lst
2018 (count 0))
2019 (while (and (< count f-height) entries)
2020 (let ((str (car entries)))
2021 (push (cons
2022 (if (> (length str) bookmark-menu-length)
2023 (substring str 0 bookmark-menu-length)
2024 str)
2025 str)
2026 lst)
2027 (setq entries (cdr entries))
2028 (setq count (1+ count))))
2029 (setq iter (1+ iter))
2030 (push (cons
2031 (format "-*- %s (%d) -*-" name iter)
2032 (nreverse lst))
2033 pane-list)))
d32ff76a 2034
175d0960
SM
2035 ;; Popup the menu and return the string.
2036 (x-popup-menu event (cons (concat "-*- " name " -*-")
2037 (nreverse pane-list)))))
e3437989 2038
b3bf02fa 2039
d22d6453
RS
2040;; Thanks to Roland McGrath for fixing menubar.el so that the
2041;; following works, and for explaining what to do to make it work.
b3bf02fa 2042
7af04c89
RS
2043;; We MUST autoload EACH form used to set up this variable's value, so
2044;; that the whole job is done in loaddefs.el.
b3bf02fa 2045
5e0e5feb 2046;; Emacs menubar stuff.
09fd6588 2047
7af04c89 2048;;;###autoload
175d0960
SM
2049(defvar menu-bar-bookmark-map
2050 (let ((map (make-sparse-keymap "Bookmark functions")))
2051 (define-key map [load] '("Load a Bookmark File..." . bookmark-load))
2052 (define-key map [write] '("Save Bookmarks As..." . bookmark-write))
2053 (define-key map [save] '("Save Bookmarks" . bookmark-save))
2054 (define-key map [edit] '("Edit Bookmark List" . bookmark-bmenu-list))
b2a664c0
JL
2055 (define-key map [delete] '("Delete Bookmark..." . bookmark-delete))
2056 (define-key map [rename] '("Rename Bookmark..." . bookmark-rename))
2057 (define-key map [locate] '("Insert Location..." . bookmark-locate))
2058 (define-key map [insert] '("Insert Contents..." . bookmark-insert))
2059 (define-key map [set] '("Set Bookmark..." . bookmark-set))
2060 (define-key map [jump] '("Jump to Bookmark..." . bookmark-jump))
175d0960 2061 map))
09fd6588 2062
7af04c89 2063;;;###autoload
175d0960 2064(defalias 'menu-bar-bookmark-map menu-bar-bookmark-map)
e3437989 2065
09fd6588
KF
2066;; make bookmarks appear toward the right side of the menu.
2067(if (boundp 'menu-bar-final-items)
dbe99ae9 2068 (if menu-bar-final-items
09fd6588
KF
2069 (setq menu-bar-final-items
2070 (cons 'bookmark menu-bar-final-items)))
2071 (setq menu-bar-final-items '(bookmark)))
2072
e3437989
RS
2073;;;; end bookmark menu stuff ;;;;
2074
2075\f
43f8b275 2076;; Load Hook
e3437989 2077(defvar bookmark-load-hook nil
175d0960 2078 "Hook run at the end of loading bookmark.")
e3437989 2079
43f8b275 2080;; Exit Hook, called from kill-emacs-hook
6192b604 2081(defvar bookmark-exit-hook nil
d32ff76a
JB
2082 "Hook run when Emacs exits.")
2083
2084(define-obsolete-variable-alias 'bookmark-exit-hooks 'bookmark-exit-hook "22.1")
dbe99ae9 2085
6192b604
KF
2086(defun bookmark-exit-hook-internal ()
2087 "Save bookmark state, if necessary, at Emacs exit time.
d32ff76a
JB
2088This also runs `bookmark-exit-hook'."
2089 (run-hooks 'bookmark-exit-hook)
175d0960
SM
2090 (and bookmark-alist
2091 (bookmark-time-to-save-p t)
2092 (bookmark-save)))
6192b604
KF
2093
2094(add-hook 'kill-emacs-hook 'bookmark-exit-hook-internal)
2095
a35809ba
JB
2096(defun bookmark-unload-function ()
2097 "Unload the Bookmark library."
2098 (when bookmark-save-flag (bookmark-save))
2099 ;; continue standard unloading
2100 nil)
2101
6192b604 2102
e3437989 2103(run-hooks 'bookmark-load-hook)
b3bf02fa 2104
b3bf02fa 2105(provide 'bookmark)
dbe99ae9 2106
3da360a7 2107;; arch-tag: 139f519a-dd0c-4b8d-8b5d-f9fcf53ca8f6
11eb4275 2108;;; bookmark.el ends here