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