* image-mode.el (image-toggle-display):
[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,
ae940284 4;; 2004, 2005, 2006, 2007, 2008, 2009 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"
9201cc28 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.
9201cc28 896 (abbreviate-file-name
3889f0fa
SM
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)
e3f36d03
SM
1304 (insert "(")
1305 ;; Rather than a single call to `pp' we make one per bookmark.
1306 ;; Apparently `pp' has a poor algorithmic complexity, so this
1307 ;; scales a lot better. bug#4485.
1308 (dolist (i bookmark-alist) (pp i (current-buffer)))
1309 (insert ")")
43f8b275
SM
1310 (let ((version-control
1311 (cond
1312 ((null bookmark-version-control) nil)
1313 ((eq 'never bookmark-version-control) 'never)
1314 ((eq 'nospecial bookmark-version-control) version-control)
1315 (t t))))
1316 (condition-case nil
1317 (write-region (point-min) (point-max) file)
1318 (file-error (message "Can't write %s" file)))
1319 (kill-buffer (current-buffer))
1320 (bookmark-maybe-message
1321 "Saving bookmarks to file %s...done" file)))))
e3437989 1322
d22d6453 1323
91169ba7
RS
1324(defun bookmark-import-new-list (new-list)
1325 ;; Walk over the new list, adding each individual bookmark
1326 ;; carefully. "Carefully" means checking against the existing
1327 ;; bookmark-alist and renaming the new bookmarks with <N> extensions
1328 ;; as necessary.
1329 (let ((lst new-list)
1330 (names (bookmark-all-names)))
1331 (while lst
1332 (let* ((full-record (car lst)))
1333 (bookmark-maybe-rename full-record names)
1334 (setq bookmark-alist (nconc bookmark-alist (list full-record)))
1335 (setq names (cons (bookmark-name-from-full-record full-record) names))
1336 (setq lst (cdr lst))))))
1337
1338
1339(defun bookmark-maybe-rename (full-record names)
1340 ;; just a helper for bookmark-import-new-list; it is only for
1341 ;; readability that this is not inlined.
1342 ;;
1343 ;; Once this has found a free name, it sets full-record to that
1344 ;; name.
1345 (let ((found-name (bookmark-name-from-full-record full-record)))
1346 (if (member found-name names)
1347 ;; We've got a conflict, so generate a new name
1348 (let ((count 2)
1349 (new-name found-name))
1350 (while (member new-name names)
1351 (setq new-name (concat found-name (format "<%d>" count)))
1352 (setq count (1+ count)))
1353 (bookmark-set-name full-record new-name)))))
1354
1355
d22d6453 1356;;;###autoload
91169ba7 1357(defun bookmark-load (file &optional overwrite no-msg)
9aef3b21
RS
1358 "Load bookmarks from FILE (which must be in bookmark format).
1359Appends loaded bookmarks to the front of the list of bookmarks. If
91169ba7 1360optional second argument OVERWRITE is non-nil, existing bookmarks are
9aef3b21
RS
1361destroyed. Optional third arg NO-MSG means don't display any messages
1362while loading.
b3bf02fa
RS
1363
1364If you load a file that doesn't contain a proper bookmark alist, you
9aef3b21 1365will corrupt Emacs's bookmark list. Generally, you should only load
b3bf02fa 1366in files that were created with the bookmark functions in the first
e3437989 1367place. Your own personal bookmark file, `~/.emacs.bmk', is
8027e2ad 1368maintained automatically by Emacs; you shouldn't need to load it
91169ba7
RS
1369explicitly.
1370
1371If you load a file containing bookmarks with the same names as
1372bookmarks already present in your Emacs, the new bookmarks will get
1373unique numeric suffixes \"<2>\", \"<3>\", ... following the same
1374method buffers use to resolve name collisions."
b3bf02fa 1375 (interactive
e3437989
RS
1376 (list (read-file-name
1377 (format "Load bookmarks from: (%s) "
dbe99ae9 1378 bookmark-default-file)
e3437989
RS
1379 ;;Default might not be used often,
1380 ;;but there's no better default, and
1381 ;;I guess it's better than none at all.
1382 "~/" bookmark-default-file 'confirm)))
b3bf02fa 1383 (setq file (expand-file-name file))
43f8b275
SM
1384 (if (not (file-readable-p file))
1385 (error "Cannot read bookmark file %s" file)
1386 (if (null no-msg)
1387 (bookmark-maybe-message "Loading bookmarks from %s..." file))
1388 (with-current-buffer (let ((enable-local-variables nil))
1389 (find-file-noselect file))
1390 (goto-char (point-min))
1391 (bookmark-maybe-upgrade-file-format)
1392 (let ((blist (bookmark-alist-from-buffer)))
1393 (if (listp blist)
1394 (progn
1395 (if overwrite
1396 (progn
1397 (setq bookmark-alist blist)
1398 (setq bookmark-alist-modification-count 0))
1399 ;; else
1400 (bookmark-import-new-list blist)
1401 (setq bookmark-alist-modification-count
1402 (1+ bookmark-alist-modification-count)))
1403 (if (string-equal
1404 (expand-file-name bookmark-default-file)
1405 file)
1406 (setq bookmarks-already-loaded t))
1407 (bookmark-bmenu-surreptitiously-rebuild-list))
1408 (error "Invalid bookmark list in %s" file)))
1409 (kill-buffer (current-buffer)))
1410 (if (null no-msg)
1411 (bookmark-maybe-message "Loading bookmarks from %s...done" file))))
b3bf02fa 1412
d22d6453 1413
e3437989 1414\f
43f8b275
SM
1415;;; Code supporting the dired-like bookmark menu.
1416;; Prefix is "bookmark-bmenu" for "buffer-menu":
e3437989
RS
1417
1418
1419(defvar bookmark-bmenu-bookmark-column nil)
d22d6453 1420
d22d6453 1421
e3437989
RS
1422(defvar bookmark-bmenu-hidden-bookmarks ())
1423
1424
e3437989 1425(defvar bookmark-bmenu-mode-map nil)
d22d6453 1426
d22d6453 1427
e3437989 1428(if bookmark-bmenu-mode-map
d22d6453 1429 nil
e3437989
RS
1430 (setq bookmark-bmenu-mode-map (make-keymap))
1431 (suppress-keymap bookmark-bmenu-mode-map t)
31cd9611 1432 (define-key bookmark-bmenu-mode-map "q" 'quit-window)
e3437989
RS
1433 (define-key bookmark-bmenu-mode-map "v" 'bookmark-bmenu-select)
1434 (define-key bookmark-bmenu-mode-map "w" 'bookmark-bmenu-locate)
1435 (define-key bookmark-bmenu-mode-map "2" 'bookmark-bmenu-2-window)
1436 (define-key bookmark-bmenu-mode-map "1" 'bookmark-bmenu-1-window)
1437 (define-key bookmark-bmenu-mode-map "j" 'bookmark-bmenu-this-window)
fbd98d61 1438 (define-key bookmark-bmenu-mode-map "\C-c\C-c" 'bookmark-bmenu-this-window)
e3437989 1439 (define-key bookmark-bmenu-mode-map "f" 'bookmark-bmenu-this-window)
74002bdf 1440 (define-key bookmark-bmenu-mode-map "\C-m" 'bookmark-bmenu-this-window)
e3437989 1441 (define-key bookmark-bmenu-mode-map "o" 'bookmark-bmenu-other-window)
fbd98d61
KF
1442 (define-key bookmark-bmenu-mode-map "\C-o"
1443 'bookmark-bmenu-switch-other-window)
e3437989
RS
1444 (define-key bookmark-bmenu-mode-map "s" 'bookmark-bmenu-save)
1445 (define-key bookmark-bmenu-mode-map "k" 'bookmark-bmenu-delete)
1446 (define-key bookmark-bmenu-mode-map "\C-d" 'bookmark-bmenu-delete-backwards)
1447 (define-key bookmark-bmenu-mode-map "x" 'bookmark-bmenu-execute-deletions)
e3437989
RS
1448 (define-key bookmark-bmenu-mode-map "d" 'bookmark-bmenu-delete)
1449 (define-key bookmark-bmenu-mode-map " " 'next-line)
1450 (define-key bookmark-bmenu-mode-map "n" 'next-line)
1451 (define-key bookmark-bmenu-mode-map "p" 'previous-line)
1452 (define-key bookmark-bmenu-mode-map "\177" 'bookmark-bmenu-backup-unmark)
1453 (define-key bookmark-bmenu-mode-map "?" 'describe-mode)
1454 (define-key bookmark-bmenu-mode-map "u" 'bookmark-bmenu-unmark)
1455 (define-key bookmark-bmenu-mode-map "m" 'bookmark-bmenu-mark)
dbe99ae9 1456 (define-key bookmark-bmenu-mode-map "l" 'bookmark-bmenu-load)
e3437989 1457 (define-key bookmark-bmenu-mode-map "r" 'bookmark-bmenu-rename)
037b0a87 1458 (define-key bookmark-bmenu-mode-map "R" 'bookmark-bmenu-relocate)
e3437989
RS
1459 (define-key bookmark-bmenu-mode-map "t" 'bookmark-bmenu-toggle-filenames)
1460 (define-key bookmark-bmenu-mode-map "a" 'bookmark-bmenu-show-annotation)
1461 (define-key bookmark-bmenu-mode-map "A" 'bookmark-bmenu-show-all-annotations)
7e510a5e
RS
1462 (define-key bookmark-bmenu-mode-map "e" 'bookmark-bmenu-edit-annotation)
1463 (define-key bookmark-bmenu-mode-map [mouse-2]
1464 'bookmark-bmenu-other-window-with-mouse))
e3437989 1465
dbe99ae9 1466
e3437989
RS
1467
1468;; Bookmark Buffer Menu mode is suitable only for specially formatted
1469;; data.
1470(put 'bookmark-bmenu-mode 'mode-class 'special)
1471
1472
1473;; todo: need to display whether or not bookmark exists as a buffer in
dbe99ae9 1474;; flag column.
d22d6453
RS
1475
1476;; Format:
e3437989
RS
1477;; FLAGS BOOKMARK [ LOCATION ]
1478
1479
1480(defun bookmark-bmenu-surreptitiously-rebuild-list ()
1481 "Rebuild the Bookmark List if it exists.
1482Don't affect the buffer ring order."
1483 (if (get-buffer "*Bookmark List*")
1484 (save-excursion
dbe99ae9 1485 (save-window-excursion
e3437989 1486 (bookmark-bmenu-list)))))
d22d6453 1487
d22d6453
RS
1488
1489;;;###autoload
e3437989 1490(defun bookmark-bmenu-list ()
d22d6453
RS
1491 "Display a list of existing bookmarks.
1492The list is displayed in a buffer named `*Bookmark List*'.
e3437989
RS
1493The leftmost column displays a D if the bookmark is flagged for
1494deletion, or > if it is flagged for displaying."
d22d6453 1495 (interactive)
e3437989
RS
1496 (bookmark-maybe-load-default-file)
1497 (if (interactive-p)
1498 (switch-to-buffer (get-buffer-create "*Bookmark List*"))
1499 (set-buffer (get-buffer-create "*Bookmark List*")))
175d0960
SM
1500 (let ((inhibit-read-only t))
1501 (erase-buffer)
d22d6453 1502 (insert "% Bookmark\n- --------\n")
37789292
RF
1503 (add-text-properties (point-min) (point)
1504 '(font-lock-face bookmark-menu-heading))
76865665 1505 (mapc
e3437989 1506 (lambda (full-record)
3b526bae 1507 ;; if a bookmark has an annotation, prepend a "*"
e3437989
RS
1508 ;; in the list of bookmarks.
1509 (let ((annotation (bookmark-get-annotation
1510 (bookmark-name-from-full-record full-record))))
91169ba7 1511 (if (and annotation (not (string-equal annotation "")))
e3437989
RS
1512 (insert " *")
1513 (insert " "))
7e510a5e
RS
1514 (let ((start (point)))
1515 (insert (bookmark-name-from-full-record full-record))
59cfe8b9 1516 (if (and (display-color-p) (display-mouse-p))
8b1b6461
RF
1517 (add-text-properties
1518 start
1519 (save-excursion (re-search-backward
1520 "[^ \t]")
1521 (1+ (point)))
1522 '(mouse-face highlight
1523 follow-link t
1524 help-echo "mouse-2: go to this bookmark in other window")))
7e510a5e
RS
1525 (insert "\n")
1526 )))
1de49d4e 1527 (bookmark-maybe-sort-alist)))
d22d6453
RS
1528 (goto-char (point-min))
1529 (forward-line 2)
e3437989
RS
1530 (bookmark-bmenu-mode)
1531 (if bookmark-bmenu-toggle-filenames
1532 (bookmark-bmenu-toggle-filenames t)))
1533
1534;;;###autoload
1535(defalias 'list-bookmarks 'bookmark-bmenu-list)
1536;;;###autoload
1537(defalias 'edit-bookmarks 'bookmark-bmenu-list)
d22d6453 1538
e3437989
RS
1539
1540
1541(defun bookmark-bmenu-mode ()
d22d6453
RS
1542 "Major mode for editing a list of bookmarks.
1543Each line describes one of the bookmarks in Emacs.
1544Letters do not insert themselves; instead, they are commands.
3b526bae 1545Bookmark names preceded by a \"*\" have annotations.
e3437989
RS
1546\\<bookmark-bmenu-mode-map>
1547\\[bookmark-bmenu-mark] -- mark bookmark to be displayed.
1548\\[bookmark-bmenu-select] -- select bookmark of line point is on.
1549 Also show bookmarks marked using m in other windows.
1550\\[bookmark-bmenu-toggle-filenames] -- toggle displaying of filenames (they may obscure long bookmark names).
1551\\[bookmark-bmenu-locate] -- display (in minibuffer) location of this bookmark.
1552\\[bookmark-bmenu-1-window] -- select this bookmark in full-frame window.
1553\\[bookmark-bmenu-2-window] -- select this bookmark in one window,
d22d6453 1554 together with bookmark selected before this one in another window.
e3437989
RS
1555\\[bookmark-bmenu-this-window] -- select this bookmark in place of the bookmark menu buffer.
1556\\[bookmark-bmenu-other-window] -- select this bookmark in another window,
d22d6453 1557 so the bookmark menu bookmark remains visible in its window.
e3437989 1558\\[bookmark-bmenu-switch-other-window] -- switch the other window to this bookmark.
dbe99ae9 1559\\[bookmark-bmenu-rename] -- rename this bookmark \(prompts for new name\).
037b0a87 1560\\[bookmark-bmenu-relocate] -- relocate this bookmark's file \(prompts for new file\).
e3437989 1561\\[bookmark-bmenu-delete] -- mark this bookmark to be deleted, and move down.
dbe99ae9 1562\\[bookmark-bmenu-delete-backwards] -- mark this bookmark to be deleted, and move up.
60d0378e 1563\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[bookmark-bmenu-delete]'.
e3437989 1564\\[bookmark-bmenu-save] -- save the current bookmark list in the default file.
d22d6453 1565 With a prefix arg, prompts for a file to save in.
e3437989
RS
1566\\[bookmark-bmenu-load] -- load in a file of bookmarks (prompts for file.)
1567\\[bookmark-bmenu-unmark] -- remove all kinds of marks from current line.
d22d6453 1568 With prefix argument, also move up one line.
e3437989
RS
1569\\[bookmark-bmenu-backup-unmark] -- back up a line and remove marks.
1570\\[bookmark-bmenu-show-annotation] -- show the annotation, if it exists, for the current bookmark
1571 in another buffer.
1572\\[bookmark-bmenu-show-all-annotations] -- show the annotations of all bookmarks in another buffer.
1573\\[bookmark-bmenu-edit-annotation] -- edit the annotation for the current bookmark."
d22d6453 1574 (kill-all-local-variables)
e3437989 1575 (use-local-map bookmark-bmenu-mode-map)
d22d6453
RS
1576 (setq truncate-lines t)
1577 (setq buffer-read-only t)
e3437989 1578 (setq major-mode 'bookmark-bmenu-mode)
d22d6453 1579 (setq mode-name "Bookmark Menu")
f33cee85 1580 (run-mode-hooks 'bookmark-bmenu-mode-hook))
d22d6453 1581
e3437989 1582
4eadcdf8 1583(defun bookmark-bmenu-toggle-filenames (&optional show)
d22d6453
RS
1584 "Toggle whether filenames are shown in the bookmark list.
1585Optional argument SHOW means show them unconditionally."
1586 (interactive)
1587 (cond
4eadcdf8 1588 (show
e3437989
RS
1589 (setq bookmark-bmenu-toggle-filenames nil)
1590 (bookmark-bmenu-show-filenames)
1591 (setq bookmark-bmenu-toggle-filenames t))
1592 (bookmark-bmenu-toggle-filenames
1593 (bookmark-bmenu-hide-filenames)
1594 (setq bookmark-bmenu-toggle-filenames nil))
d22d6453 1595 (t
e3437989
RS
1596 (bookmark-bmenu-show-filenames)
1597 (setq bookmark-bmenu-toggle-filenames t))))
1598
d22d6453 1599
e3437989
RS
1600(defun bookmark-bmenu-show-filenames (&optional force)
1601 (if (and (not force) bookmark-bmenu-toggle-filenames)
d22d6453
RS
1602 nil ;already shown, so do nothing
1603 (save-excursion
1604 (save-window-excursion
1605 (goto-char (point-min))
1606 (forward-line 2)
e3437989 1607 (setq bookmark-bmenu-hidden-bookmarks ())
175d0960 1608 (let ((inhibit-read-only t))
d22d6453 1609 (while (< (point) (point-max))
e3437989
RS
1610 (let ((bmrk (bookmark-bmenu-bookmark)))
1611 (setq bookmark-bmenu-hidden-bookmarks
1612 (cons bmrk bookmark-bmenu-hidden-bookmarks))
7e510a5e
RS
1613 (let ((start (save-excursion (end-of-line) (point))))
1614 (move-to-column bookmark-bmenu-file-column t)
1615 ;; Strip off `mouse-face' from the white spaces region.
59cfe8b9 1616 (if (and (display-color-p) (display-mouse-p))
7e510a5e 1617 (remove-text-properties start (point)
2fbb6576 1618 '(mouse-face nil help-echo nil))))
7e510a5e 1619 (delete-region (point) (progn (end-of-line) (point)))
d22d6453 1620 (insert " ")
4c0b5ad1
KF
1621 ;; Pass the NO-HISTORY arg:
1622 (bookmark-insert-location bmrk t)
d22d6453
RS
1623 (forward-line 1))))))))
1624
e3437989
RS
1625
1626(defun bookmark-bmenu-hide-filenames (&optional force)
1627 (if (and (not force) bookmark-bmenu-toggle-filenames)
d22d6453
RS
1628 ;; nothing to hide if above is nil
1629 (save-excursion
1630 (save-window-excursion
1631 (goto-char (point-min))
1632 (forward-line 2)
e3437989
RS
1633 (setq bookmark-bmenu-hidden-bookmarks
1634 (nreverse bookmark-bmenu-hidden-bookmarks))
d22d6453
RS
1635 (save-excursion
1636 (goto-char (point-min))
1637 (search-forward "Bookmark")
1638 (backward-word 1)
e3437989 1639 (setq bookmark-bmenu-bookmark-column (current-column)))
d22d6453 1640 (save-excursion
175d0960 1641 (let ((inhibit-read-only t))
e3437989
RS
1642 (while bookmark-bmenu-hidden-bookmarks
1643 (move-to-column bookmark-bmenu-bookmark-column t)
1644 (bookmark-kill-line)
7e510a5e
RS
1645 (let ((start (point)))
1646 (insert (car bookmark-bmenu-hidden-bookmarks))
59cfe8b9 1647 (if (and (display-color-p) (display-mouse-p))
8b1b6461
RF
1648 (add-text-properties
1649 start
1650 (save-excursion (re-search-backward
1651 "[^ \t]")
1652 (1+ (point)))
1653 '(mouse-face highlight
1654 follow-link t
1655 help-echo
1656 "mouse-2: go to this bookmark in other window"))))
e3437989
RS
1657 (setq bookmark-bmenu-hidden-bookmarks
1658 (cdr bookmark-bmenu-hidden-bookmarks))
d22d6453
RS
1659 (forward-line 1))))))))
1660
e3437989 1661
e3437989 1662(defun bookmark-bmenu-check-position ()
91169ba7
RS
1663 ;; Returns non-nil if on a line with a bookmark.
1664 ;; (The actual value returned is bookmark-alist).
1665 ;; Else reposition and try again, else return nil.
d22d6453
RS
1666 (cond ((< (count-lines (point-min) (point)) 2)
1667 (goto-char (point-min))
1668 (forward-line 2)
91169ba7 1669 bookmark-alist)
d22d6453
RS
1670 ((and (bolp) (eobp))
1671 (beginning-of-line 0)
91169ba7 1672 bookmark-alist)
d22d6453 1673 (t
91169ba7 1674 bookmark-alist)))
d22d6453 1675
e3437989
RS
1676
1677(defun bookmark-bmenu-bookmark ()
d22d6453 1678 ;; return a string which is bookmark of this line.
e3437989 1679 (if (bookmark-bmenu-check-position)
d22d6453
RS
1680 (save-excursion
1681 (save-window-excursion
1682 (goto-char (point-min))
1683 (search-forward "Bookmark")
1684 (backward-word 1)
e3437989
RS
1685 (setq bookmark-bmenu-bookmark-column (current-column)))))
1686 (if bookmark-bmenu-toggle-filenames
1687 (bookmark-bmenu-hide-filenames))
d22d6453
RS
1688 (save-excursion
1689 (save-window-excursion
1690 (beginning-of-line)
e3437989 1691 (forward-char bookmark-bmenu-bookmark-column)
d22d6453 1692 (prog1
dbe99ae9
SS
1693 (buffer-substring-no-properties (point)
1694 (progn
d22d6453
RS
1695 (end-of-line)
1696 (point)))
1697 ;; well, this is certainly crystal-clear:
e3437989
RS
1698 (if bookmark-bmenu-toggle-filenames
1699 (bookmark-bmenu-toggle-filenames t))))))
d22d6453 1700
e3437989
RS
1701
1702(defun bookmark-show-annotation (bookmark)
1703 "Display the annotation for bookmark named BOOKMARK in a buffer,
1704if an annotation exists."
1705 (let ((annotation (bookmark-get-annotation bookmark)))
91169ba7
RS
1706 (if (and annotation (not (string-equal annotation "")))
1707 (save-excursion
1708 (let ((old-buf (current-buffer)))
1709 (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t)
1710 (delete-region (point-min) (point-max))
1711 ;; (insert (concat "Annotation for bookmark '" bookmark "':\n\n"))
1712 (insert annotation)
1713 (goto-char (point-min))
1714 (pop-to-buffer old-buf))))))
e3437989
RS
1715
1716
1717(defun bookmark-show-all-annotations ()
1718 "Display the annotations for all bookmarks in a buffer."
1719 (let ((old-buf (current-buffer)))
1720 (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t)
1721 (delete-region (point-min) (point-max))
76865665 1722 (mapc
e3437989
RS
1723 (lambda (full-record)
1724 (let* ((name (bookmark-name-from-full-record full-record))
1725 (ann (bookmark-get-annotation name)))
1726 (insert (concat name ":\n"))
91169ba7 1727 (if (and ann (not (string-equal ann "")))
e3437989
RS
1728 ;; insert the annotation, indented by 4 spaces.
1729 (progn
fd5306d2
TTN
1730 (save-excursion (insert ann) (unless (bolp)
1731 (insert "\n")))
e3437989
RS
1732 (while (< (point) (point-max))
1733 (beginning-of-line) ; paranoia
1734 (insert " ")
1735 (forward-line)
1736 (end-of-line))))))
1737 bookmark-alist)
1738 (goto-char (point-min))
1739 (pop-to-buffer old-buf)))
1740
1741
1742(defun bookmark-bmenu-mark ()
5e0e5feb 1743 "Mark bookmark on this line to be displayed by \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-select]."
d22d6453
RS
1744 (interactive)
1745 (beginning-of-line)
e3437989 1746 (if (bookmark-bmenu-check-position)
175d0960 1747 (let ((inhibit-read-only t))
d22d6453
RS
1748 (delete-char 1)
1749 (insert ?>)
91169ba7
RS
1750 (forward-line 1)
1751 (bookmark-bmenu-check-position))))
d22d6453 1752
e3437989
RS
1753
1754(defun bookmark-bmenu-select ()
d22d6453 1755 "Select this line's bookmark; also display bookmarks marked with `>'.
e3437989 1756You can mark bookmarks with the \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-mark] command."
d22d6453 1757 (interactive)
e3437989
RS
1758 (if (bookmark-bmenu-check-position)
1759 (let ((bmrk (bookmark-bmenu-bookmark))
dbe99ae9 1760 (menu (current-buffer))
d22d6453
RS
1761 (others ())
1762 tem)
1763 (goto-char (point-min))
1764 (while (re-search-forward "^>" nil t)
e3437989 1765 (setq tem (bookmark-bmenu-bookmark))
175d0960 1766 (let ((inhibit-read-only t))
d22d6453 1767 (delete-char -1)
d32ff76a 1768 (insert ?\s))
dbe99ae9
SS
1769 (or (string-equal tem bmrk)
1770 (member tem others)
d22d6453
RS
1771 (setq others (cons tem others))))
1772 (setq others (nreverse others)
1773 tem (/ (1- (frame-height)) (1+ (length others))))
1774 (delete-other-windows)
1775 (bookmark-jump bmrk)
1776 (bury-buffer menu)
4eadcdf8
RS
1777 (if others
1778 (while others
1779 (split-window nil tem)
1780 (other-window 1)
1781 (bookmark-jump (car others))
1782 (setq others (cdr others)))
d22d6453
RS
1783 (other-window 1)))))
1784
e3437989
RS
1785
1786(defun bookmark-bmenu-save (parg)
d22d6453
RS
1787 "Save the current list into a bookmark file.
1788With a prefix arg, prompts for a file to save them in."
1789 (interactive "P")
1790 (save-excursion
1791 (save-window-excursion
1792 (bookmark-save parg))))
1793
e3437989
RS
1794
1795(defun bookmark-bmenu-load ()
1796 "Load the bookmark file and rebuild the bookmark menu-buffer."
d22d6453 1797 (interactive)
e3437989 1798 (if (bookmark-bmenu-check-position)
d22d6453
RS
1799 (save-excursion
1800 (save-window-excursion
e3437989 1801 ;; This will call `bookmark-bmenu-list'
d22d6453
RS
1802 (call-interactively 'bookmark-load)))))
1803
e3437989
RS
1804
1805(defun bookmark-bmenu-1-window ()
d22d6453
RS
1806 "Select this line's bookmark, alone, in full frame."
1807 (interactive)
e3437989 1808 (if (bookmark-bmenu-check-position)
d22d6453 1809 (progn
e3437989 1810 (bookmark-jump (bookmark-bmenu-bookmark))
d22d6453
RS
1811 (bury-buffer (other-buffer))
1812 (delete-other-windows))))
1813
e3437989
RS
1814
1815(defun bookmark-bmenu-2-window ()
d22d6453
RS
1816 "Select this line's bookmark, with previous buffer in second window."
1817 (interactive)
e3437989
RS
1818 (if (bookmark-bmenu-check-position)
1819 (let ((bmrk (bookmark-bmenu-bookmark))
d22d6453
RS
1820 (menu (current-buffer))
1821 (pop-up-windows t))
1822 (delete-other-windows)
1823 (switch-to-buffer (other-buffer))
43f8b275
SM
1824 (let ((bookmark-automatically-show-annotations nil)) ;FIXME: needed?
1825 (bookmark--jump-via bmrk 'pop-to-buffer))
d22d6453
RS
1826 (bury-buffer menu))))
1827
e3437989
RS
1828
1829(defun bookmark-bmenu-this-window ()
d22d6453
RS
1830 "Select this line's bookmark in this window."
1831 (interactive)
e3437989
RS
1832 (if (bookmark-bmenu-check-position)
1833 (bookmark-jump (bookmark-bmenu-bookmark))))
d22d6453 1834
e3437989
RS
1835
1836(defun bookmark-bmenu-other-window ()
d22d6453
RS
1837 "Select this line's bookmark in other window, leaving bookmark menu visible."
1838 (interactive)
e3437989
RS
1839 (let ((bookmark (bookmark-bmenu-bookmark)))
1840 (if (bookmark-bmenu-check-position)
43f8b275
SM
1841 (let ((bookmark-automatically-show-annotations t)) ;FIXME: needed?
1842 (bookmark--jump-via bookmark 'switch-to-buffer-other-window)))))
e40e3151
KF
1843
1844
1845(defun bookmark-bmenu-switch-other-window ()
1846 "Make the other window select this line's bookmark.
1847The current window remains selected."
1848 (interactive)
e197b151
RS
1849 (let ((bookmark (bookmark-bmenu-bookmark))
1850 (pop-up-windows t)
dbe99ae9 1851 same-window-buffer-names
e197b151 1852 same-window-regexps)
e40e3151 1853 (if (bookmark-bmenu-check-position)
43f8b275
SM
1854 (let ((bookmark-automatically-show-annotations t)) ;FIXME: needed?
1855 (bookmark--jump-via bookmark 'display-buffer)))))
e3437989 1856
7e510a5e
RS
1857(defun bookmark-bmenu-other-window-with-mouse (event)
1858 "Select bookmark at the mouse pointer in other window, leaving bookmark menu visible."
1859 (interactive "e")
43f8b275 1860 (with-current-buffer (window-buffer (posn-window (event-end event)))
7e510a5e
RS
1861 (save-excursion
1862 (goto-char (posn-point (event-end event)))
1863 (bookmark-bmenu-other-window))))
1864
e3437989
RS
1865
1866(defun bookmark-bmenu-show-annotation ()
1867 "Show the annotation for the current bookmark in another window."
1868 (interactive)
1869 (let ((bookmark (bookmark-bmenu-bookmark)))
1870 (if (bookmark-bmenu-check-position)
1871 (bookmark-show-annotation bookmark))))
d22d6453 1872
e3437989
RS
1873
1874(defun bookmark-bmenu-show-all-annotations ()
1875 "Show the annotation for all bookmarks in another window."
1876 (interactive)
1877 (bookmark-show-all-annotations))
1878
1879
1880(defun bookmark-bmenu-edit-annotation ()
1881 "Edit the annotation for the current bookmark in another window."
1882 (interactive)
1883 (let ((bookmark (bookmark-bmenu-bookmark)))
1884 (if (bookmark-bmenu-check-position)
1885 (bookmark-edit-annotation bookmark))))
1886
1887
e3437989 1888(defun bookmark-bmenu-unmark (&optional backup)
d22d6453 1889 "Cancel all requested operations on bookmark on this line and move down.
4eadcdf8 1890Optional BACKUP means move up."
d22d6453
RS
1891 (interactive "P")
1892 (beginning-of-line)
e3437989 1893 (if (bookmark-bmenu-check-position)
d22d6453 1894 (progn
175d0960 1895 (let ((inhibit-read-only t))
d22d6453
RS
1896 (delete-char 1)
1897 ;; any flags to reset according to circumstances? How about a
1898 ;; flag indicating whether this bookmark is being visited?
1899 ;; well, we don't have this now, so maybe later.
1900 (insert " "))
91169ba7
RS
1901 (forward-line (if backup -1 1))
1902 (bookmark-bmenu-check-position))))
d22d6453 1903
e3437989
RS
1904
1905(defun bookmark-bmenu-backup-unmark ()
d22d6453
RS
1906 "Move up and cancel all requested operations on bookmark on line above."
1907 (interactive)
1908 (forward-line -1)
e3437989 1909 (if (bookmark-bmenu-check-position)
d22d6453 1910 (progn
e3437989 1911 (bookmark-bmenu-unmark)
91169ba7
RS
1912 (forward-line -1)
1913 (bookmark-bmenu-check-position))))
d22d6453 1914
e3437989
RS
1915
1916(defun bookmark-bmenu-delete ()
5e0e5feb
RS
1917 "Mark bookmark on this line to be deleted.
1918To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-execute-deletions]."
d22d6453
RS
1919 (interactive)
1920 (beginning-of-line)
e3437989 1921 (if (bookmark-bmenu-check-position)
175d0960 1922 (let ((inhibit-read-only t))
d22d6453
RS
1923 (delete-char 1)
1924 (insert ?D)
91169ba7
RS
1925 (forward-line 1)
1926 (bookmark-bmenu-check-position))))
d22d6453 1927
e3437989
RS
1928
1929(defun bookmark-bmenu-delete-backwards ()
5e0e5feb
RS
1930 "Mark bookmark on this line to be deleted, then move up one line.
1931To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-execute-deletions]."
d22d6453 1932 (interactive)
e3437989 1933 (bookmark-bmenu-delete)
d22d6453 1934 (forward-line -2)
e3437989 1935 (if (bookmark-bmenu-check-position)
91169ba7
RS
1936 (forward-line 1))
1937 (bookmark-bmenu-check-position))
d22d6453 1938
e3437989
RS
1939
1940(defun bookmark-bmenu-execute-deletions ()
d22d6453
RS
1941 "Delete bookmarks marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
1942 (interactive)
60d0378e 1943 (message "Deleting bookmarks...")
e3437989
RS
1944 (let ((hide-em bookmark-bmenu-toggle-filenames)
1945 (o-point (point))
1946 (o-str (save-excursion
1947 (beginning-of-line)
1948 (if (looking-at "^D")
1949 nil
1950 (buffer-substring
1951 (point)
1952 (progn (end-of-line) (point))))))
1953 (o-col (current-column)))
1954 (if hide-em (bookmark-bmenu-hide-filenames))
1955 (setq bookmark-bmenu-toggle-filenames nil)
d22d6453
RS
1956 (goto-char (point-min))
1957 (forward-line 1)
e3437989
RS
1958 (while (re-search-forward "^D" (point-max) t)
1959 (bookmark-delete (bookmark-bmenu-bookmark) t)) ; pass BATCH arg
1960 (bookmark-bmenu-list)
1961 (setq bookmark-bmenu-toggle-filenames hide-em)
1962 (if bookmark-bmenu-toggle-filenames
1963 (bookmark-bmenu-toggle-filenames t))
1964 (if o-str
1965 (progn
1966 (goto-char (point-min))
1967 (search-forward o-str)
1968 (beginning-of-line)
1969 (forward-char o-col))
1970 (goto-char o-point))
1971 (beginning-of-line)
1972 (setq bookmark-alist-modification-count
1973 (1+ bookmark-alist-modification-count))
1974 (if (bookmark-time-to-save-p)
60d0378e
KF
1975 (bookmark-save))
1976 (message "Deleting bookmarks...done")
1977 ))
e3437989
RS
1978
1979
1980(defun bookmark-bmenu-rename ()
d22d6453
RS
1981 "Rename bookmark on current line. Prompts for a new name."
1982 (interactive)
e3437989
RS
1983 (if (bookmark-bmenu-check-position)
1984 (let ((bmrk (bookmark-bmenu-bookmark))
d22d6453
RS
1985 (thispoint (point)))
1986 (bookmark-rename bmrk)
e3437989 1987 (bookmark-bmenu-list)
d22d6453
RS
1988 (goto-char thispoint))))
1989
e3437989
RS
1990
1991(defun bookmark-bmenu-locate ()
d22d6453
RS
1992 "Display location of this bookmark. Displays in the minibuffer."
1993 (interactive)
e3437989
RS
1994 (if (bookmark-bmenu-check-position)
1995 (let ((bmrk (bookmark-bmenu-bookmark)))
8a26c165 1996 (message "%s" (bookmark-location bmrk)))))
e3437989 1997
037b0a87
KF
1998(defun bookmark-bmenu-relocate ()
1999 "Change the file path of the bookmark on the current line,
2000 prompting with completion for the new path."
2001 (interactive)
2002 (if (bookmark-bmenu-check-position)
2003 (let ((bmrk (bookmark-bmenu-bookmark))
2004 (thispoint (point)))
2005 (bookmark-relocate bmrk)
2006 (goto-char thispoint))))
d22d6453 2007
e3437989
RS
2008\f
2009;;; Menu bar stuff. Prefix is "bookmark-menu".
11eb4275 2010
e3437989
RS
2011(defun bookmark-menu-popup-paned-menu (event name entries)
2012 "Pop up multi-paned menu at EVENT, return string chosen from ENTRIES.
2013That is, ENTRIES is a list of strings which appear as the choices
2014in the menu.
175d0960
SM
2015The number of panes depends on the number of entries.
2016The visible entries are truncated to `bookmark-menu-length', but the
2017strings returned are not."
2018 (let ((f-height (/ (frame-height) 2))
2019 (pane-list nil)
2020 (iter 0))
2021 (while entries
2022 (let (lst
2023 (count 0))
2024 (while (and (< count f-height) entries)
2025 (let ((str (car entries)))
2026 (push (cons
2027 (if (> (length str) bookmark-menu-length)
2028 (substring str 0 bookmark-menu-length)
2029 str)
2030 str)
2031 lst)
2032 (setq entries (cdr entries))
2033 (setq count (1+ count))))
2034 (setq iter (1+ iter))
2035 (push (cons
2036 (format "-*- %s (%d) -*-" name iter)
2037 (nreverse lst))
2038 pane-list)))
d32ff76a 2039
175d0960
SM
2040 ;; Popup the menu and return the string.
2041 (x-popup-menu event (cons (concat "-*- " name " -*-")
2042 (nreverse pane-list)))))
e3437989 2043
b3bf02fa 2044
d22d6453
RS
2045;; Thanks to Roland McGrath for fixing menubar.el so that the
2046;; following works, and for explaining what to do to make it work.
b3bf02fa 2047
7af04c89
RS
2048;; We MUST autoload EACH form used to set up this variable's value, so
2049;; that the whole job is done in loaddefs.el.
b3bf02fa 2050
5e0e5feb 2051;; Emacs menubar stuff.
09fd6588 2052
7af04c89 2053;;;###autoload
175d0960
SM
2054(defvar menu-bar-bookmark-map
2055 (let ((map (make-sparse-keymap "Bookmark functions")))
2056 (define-key map [load] '("Load a Bookmark File..." . bookmark-load))
2057 (define-key map [write] '("Save Bookmarks As..." . bookmark-write))
2058 (define-key map [save] '("Save Bookmarks" . bookmark-save))
2059 (define-key map [edit] '("Edit Bookmark List" . bookmark-bmenu-list))
b2a664c0
JL
2060 (define-key map [delete] '("Delete Bookmark..." . bookmark-delete))
2061 (define-key map [rename] '("Rename Bookmark..." . bookmark-rename))
2062 (define-key map [locate] '("Insert Location..." . bookmark-locate))
2063 (define-key map [insert] '("Insert Contents..." . bookmark-insert))
2064 (define-key map [set] '("Set Bookmark..." . bookmark-set))
2065 (define-key map [jump] '("Jump to Bookmark..." . bookmark-jump))
175d0960 2066 map))
09fd6588 2067
7af04c89 2068;;;###autoload
175d0960 2069(defalias 'menu-bar-bookmark-map menu-bar-bookmark-map)
e3437989 2070
09fd6588
KF
2071;; make bookmarks appear toward the right side of the menu.
2072(if (boundp 'menu-bar-final-items)
dbe99ae9 2073 (if menu-bar-final-items
09fd6588
KF
2074 (setq menu-bar-final-items
2075 (cons 'bookmark menu-bar-final-items)))
2076 (setq menu-bar-final-items '(bookmark)))
2077
e3437989
RS
2078;;;; end bookmark menu stuff ;;;;
2079
2080\f
43f8b275 2081;; Load Hook
e3437989 2082(defvar bookmark-load-hook nil
175d0960 2083 "Hook run at the end of loading bookmark.")
e3437989 2084
43f8b275 2085;; Exit Hook, called from kill-emacs-hook
6192b604 2086(defvar bookmark-exit-hook nil
d32ff76a
JB
2087 "Hook run when Emacs exits.")
2088
2089(define-obsolete-variable-alias 'bookmark-exit-hooks 'bookmark-exit-hook "22.1")
dbe99ae9 2090
6192b604
KF
2091(defun bookmark-exit-hook-internal ()
2092 "Save bookmark state, if necessary, at Emacs exit time.
d32ff76a
JB
2093This also runs `bookmark-exit-hook'."
2094 (run-hooks 'bookmark-exit-hook)
175d0960
SM
2095 (and bookmark-alist
2096 (bookmark-time-to-save-p t)
2097 (bookmark-save)))
6192b604
KF
2098
2099(add-hook 'kill-emacs-hook 'bookmark-exit-hook-internal)
2100
a35809ba
JB
2101(defun bookmark-unload-function ()
2102 "Unload the Bookmark library."
2103 (when bookmark-save-flag (bookmark-save))
2104 ;; continue standard unloading
2105 nil)
2106
6192b604 2107
e3437989 2108(run-hooks 'bookmark-load-hook)
b3bf02fa 2109
b3bf02fa 2110(provide 'bookmark)
dbe99ae9 2111
3da360a7 2112;; arch-tag: 139f519a-dd0c-4b8d-8b5d-f9fcf53ca8f6
11eb4275 2113;;; bookmark.el ends here