bookmark.el 50.4 KB
Newer Older
Richard M. Stallman's avatar
Richard M. Stallman committed
1 2
;;; bookmark.el --- set bookmarks, jump to them later.

3
;; Copyright (C) 1993 Free Software Foundation
Richard M. Stallman's avatar
Richard M. Stallman committed
4 5

;; Author: Karl Fogel <kfogel@cs.oberlin.edu>
Richard M. Stallman's avatar
Richard M. Stallman committed
6
;; Maintainer: Karl Fogel <kfogel@cs.oberlin.edu>
Richard M. Stallman's avatar
Richard M. Stallman committed
7
;; Created: July, 1993
Karl Fogel's avatar
Karl Fogel committed
8
;; Version: 2.5
Richard M. Stallman's avatar
Richard M. Stallman committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
;; Keywords: bookmarks, placeholders

;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

;; Thanks to David Bremner <bremner@cs.sfu.ca> for thinking of and
;; then implementing the bookmark-current-bookmark idea.  He even
Karl Fogel's avatar
Karl Fogel committed
29
;; sent *patches*, bless his soul...
Richard M. Stallman's avatar
Richard M. Stallman committed
30 31 32 33

;; Thanks to Gregory M. Saunders <saunders@cis.ohio-state.edu> for
;; fixing and improving bookmark-time-to-save-p.

Karl Fogel's avatar
Karl Fogel committed
34 35 36 37
;; Thanks go to Andrew V. Klein <avk@rtsg.mot.com> for the code that
;; sorts the alist before presenting it to the user (in list-bookmarks
;; and the menu-bar).

38 39 40 41 42
;; And much thanks to David Hughes <djh@harston.cv.com> for many small
;; suggestions and the code to implement them (like
;; Bookmark-menu-check-position, and some of the Lucid compatibility
;; stuff).

Karl Fogel's avatar
Karl Fogel committed
43 44 45 46 47
;; Kudos (whatever they are) go to Jim Blandy <jimb@cs.oberlin.edu>
;; for his eminently sensible suggestion to separate bookmark-jump
;; into bookmark-jump and bookmark-jump-noselect, which made many
;; other things cleaner as well.

48 49 50
;; Thanks to Roland McGrath for encouragement and help with defining
;; autoloads on the menu-bar.

Karl Fogel's avatar
Karl Fogel committed
51 52 53 54 55
;; Jonathan Stigelman <stig@key.amdahl.com> gave patches for default
;; values in bookmark-jump and bookmark-set.  Everybody please keep
;; all the keystrokes they save thereby and send them to him at the
;; end of each year :-)  (No, seriously, thanks Jonathan!)

Richard M. Stallman's avatar
Richard M. Stallman committed
56 57 58 59 60 61
;; Based on info-bookmark.el, by Karl Fogel and Ken Olstad
;; <olstad@msc.edu>.

;; LCD Archive Entry:
;; bookmark|Karl Fogel|kfogel@cs.oberlin.edu|
;; Setting bookmarks in files or directories, jumping to them later.|
Karl Fogel's avatar
Karl Fogel committed
62
;; 16-July-93|Version: 2.5|~/misc/bookmark.el.Z|
63 64

;; Enough with the credits already, get on to the good stuff:
Richard M. Stallman's avatar
Richard M. Stallman committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

;; FAVORITE CHINESE RESTAURANT: 
;; Boy, that's a tough one.  Probably Hong Min, or maybe Emperor's
;; Choice (both in Chicago's Chinatown).  Well, both.  How about you?

;;; Commentary on code:

;; bookmark alist format:
;;               (...
;;                (bookmark-name (filename
;;                                string-in-front
;;                                string-behind
;;                                point))
;;                ...)
;;
;; bookmark-name is the string the user gives the bookmark and
;; accesses it by from then on.  filename is the location of the file
;; in which the bookmark is set.  string-in-front is a string of
;; `bookmark-search-size' chars of context in front of the point the
;; bookmark is set at, string-behind is the same thing after the
;; point.  bookmark-jump will search for string-behind and
;; string-in-front in case the file has changed since the bookmark was
;; set.  It will attempt to place the user before the changes, if
;; there were any.
Richard M. Stallman's avatar
Richard M. Stallman committed
89
;;
90 91 92 93
;; The bookmark list is sorted lexically by default, but you can turn
;; this off by setting bookmark-sort-flag to nil.  If it is nil, then
;; the list will be presented in the order it is recorded
;; (chronologically), which is actually fairly useful as well.
Richard M. Stallman's avatar
Richard M. Stallman committed
94 95 96 97 98 99

;;; Code:

;; Added  for lucid emacs  compatibility, db
(or (fboundp 'defalias)  (fset 'defalias 'fset))

100 101 102 103 104 105 106
;; suggested for lucid compatibility by david hughes:
(or (fboundp 'frame-height)  (fset 'frame-height 'screen-height))

;; some people have C-x r set to rmail or whatever.  We don't want to
;; assume that C-x r is a prefix map just because it's distributed
;; that way...
;; These are the distribution keybindings suggested by RMS, everything
Richard M. Stallman's avatar
Richard M. Stallman committed
107
;; else will be done with M-x or the menubar:
108 109 110 111 112 113
;;;###autoload
(if (symbolp (key-binding "\C-xr"))
    nil
  (progn (define-key ctl-x-map "rb" 'bookmark-jump)
         (define-key ctl-x-map "rm" 'bookmark-set)
         (define-key ctl-x-map "rl" 'list-bookmarks)))
Richard M. Stallman's avatar
Richard M. Stallman committed
114 115 116

;; define the map, so it can be bound by those who desire to do so:

117
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
118 119 120 121 122
(defvar bookmark-map nil
  "Keymap containing bindings to bookmark functions.
It is not bound to any key by default: to bind it
so that you have a bookmark prefix, just use `global-set-key' and bind a
key of your choice to `bookmark-map'.  All interactive bookmark
Richard M. Stallman's avatar
Richard M. Stallman committed
123 124
functions have a binding in this keymap.")

125
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
126 127 128
(define-prefix-command 'bookmark-map)

;; Read the help on all of these functions for details...
129
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
130
(define-key bookmark-map "x" 'bookmark-set)
131 132 133
;;;###autoload
(define-key bookmark-map "m" 'bookmark-set) ; "m" for "mark"
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
134
(define-key bookmark-map "j" 'bookmark-jump)
135 136 137
;;;###autoload
(define-key bookmark-map "g" 'bookmark-jump) ; "g" for "go"
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
138
(define-key bookmark-map "i" 'bookmark-insert)
139 140 141
;;;###autoload
(define-key bookmark-map "e" 'edit-bookmarks)
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
142
(define-key bookmark-map "f" 'bookmark-locate) ; "f" for "find"
143
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
144
(define-key bookmark-map "r" 'bookmark-rename)
145
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
146
(define-key bookmark-map "d" 'bookmark-delete)
147
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
148
(define-key bookmark-map "l" 'bookmark-load)
149 150 151
;;;###autoload
(define-key bookmark-map "w" 'bookmark-write)
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
152 153
(define-key bookmark-map "s" 'bookmark-save)

154 155 156 157 158
(defvar bookmark-alist ()
  "Association list of bookmarks.
You probably don't want to change the value of this alist yourself;
instead, let the various bookmark functions do it for you.")

159 160
(defvar bookmarks-already-loaded nil)

Richard M. Stallman's avatar
Richard M. Stallman committed
161 162
;; just add the hook to make sure that people don't lose bookmarks
;; when they kill Emacs, unless they don't want to save them.
163
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
164 165
(add-hook 'kill-emacs-hook
          (function
166 167 168 169
           (lambda () (and (featurep 'bookmark)
                           bookmark-alist
                           (bookmark-time-to-save-p t)
                           (bookmark-save)))))
Richard M. Stallman's avatar
Richard M. Stallman committed
170 171

;; more stuff added by db.
172

Richard M. Stallman's avatar
Richard M. Stallman committed
173
(defvar bookmark-current-bookmark nil 
Richard M. Stallman's avatar
Richard M. Stallman committed
174 175
  "Name of bookmark most recently used in the current file.
It is buffer local, used to make moving a bookmark forward
Richard M. Stallman's avatar
Richard M. Stallman committed
176
through a file easier.")
Richard M. Stallman's avatar
Richard M. Stallman committed
177 178 179 180

(make-variable-buffer-local 'bookmark-current-bookmark)

(defvar bookmark-save-flag t
Richard M. Stallman's avatar
Richard M. Stallman committed
181 182 183 184 185 186 187 188 189
  "*Controls when Emacs saves bookmarks to a file.
--> Nil means never save bookmarks, except when `bookmark-save' is
    explicitly called \(\\[bookmark-save]\).
--> t means save bookmarks when Emacs is killed.
--> Otherise, it should be a number that is the frequency with which
    the bookmark list is saved \(i.e.: the number of times which
    Emacs' bookmark list may be modified before it is automatically
    saved.\).  If it is a number, Emacs will also automatically save
    bookmarks when it is killed.
Richard M. Stallman's avatar
Richard M. Stallman committed
190 191 192 193 194 195

Therefore, the way to get it to save every time you make or delete a
bookmark is to set this variable to 1 \(or 0, which produces the same
behavior.\)

To specify the file in which to save them, modify the variable
Richard M. Stallman's avatar
Richard M. Stallman committed
196
bookmark-file, which is `~/.emacs-bkmrks' by default.")
Richard M. Stallman's avatar
Richard M. Stallman committed
197 198

(defvar bookmark-alist-modification-count 0
Richard M. Stallman's avatar
Richard M. Stallman committed
199
  "Number of modifications to bookmark list since it was last saved.")
Richard M. Stallman's avatar
Richard M. Stallman committed
200 201 202 203

(defvar bookmark-file "~/.emacs-bkmrks" 
  "*File in which to save bookmarks by default.")

204 205 206 207 208 209 210
(defvar bookmark-version-control 'nospecial
  "This variable controls whether or not to make numbered backups of
the master bookmark file.  It can have four values: t, nil, never, and
nospecial.  The first three have the same meaning that they do for the
variable version-control, and the final value nospecial means just use
the value of version-control.")

Richard M. Stallman's avatar
Richard M. Stallman committed
211
(defvar bookmark-completion-ignore-case t
Richard M. Stallman's avatar
Richard M. Stallman committed
212
  "*Non-nil means bookmark functions ignore case in completion.")
Richard M. Stallman's avatar
Richard M. Stallman committed
213

214 215 216 217 218
(defvar bookmark-sort-flag t
  "*Non-nil means that bookmarks will be displayed sorted by bookmark
name.  Otherwise they will be displayed in LIFO order (that is, most
recently set ones come first, oldest ones come last).")

Richard M. Stallman's avatar
Richard M. Stallman committed
219 220
(defvar bookmark-search-size 500 
  "Length of the context strings recorded on either side of a bookmark.")
Richard M. Stallman's avatar
Richard M. Stallman committed
221 222 223 224 225

(defvar bookmark-current-point 0)
(defvar bookmark-yank-point 0)
(defvar bookmark-current-buffer nil)

226
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
227
(defun bookmark-set (&optional parg)
Richard M. Stallman's avatar
Richard M. Stallman committed
228 229 230 231 232 233 234
  "Set a bookmark named NAME inside a file.  
With prefix arg, will not overwrite a bookmark that has the same name
as NAME if such a bookmark already exists, but instead will \"push\"
the new bookmark onto the bookmark alist.  Thus the most recently set
bookmark with name NAME would be the one in effect at any given time,
but the others are still there, should you decide to delete the most
recent one.
Richard M. Stallman's avatar
Richard M. Stallman committed
235 236

To yank words from the text of the buffer and use them as part of the
Richard M. Stallman's avatar
Richard M. Stallman committed
237
bookmark name, type C-w while setting a bookmark.  Successive C-w's
Richard M. Stallman's avatar
Richard M. Stallman committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251
yank successive words.

Typing C-v inserts the name of the current file being visited. Typing
C-u inserts the name of the last bookmark used in the buffer \(as an
aid in using a single bookmark name to track your progress through a
large file\).  If no bookmark was used, then C-u behaves like C-v and
inserts the name of the file being visited.

Use \\[bookmark-delete] to remove bookmarks \(you give it a name,
and it removes only the first instance of a bookmark with that name from
the list of bookmarks.\)"
  (interactive "P")
  (if (not (bookmark-buffer-file-name))
      (error "Buffer not visiting a file or directory."))
252
  (bookmark-try-default-file)
Richard M. Stallman's avatar
Richard M. Stallman committed
253 254 255
  (setq bookmark-current-point (point))
  (setq bookmark-yank-point (point))
  (setq bookmark-current-buffer (current-buffer))
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
  (let* ((default (or bookmark-current-bookmark
                      (buffer-name (current-buffer))))
	 (str
	  (read-from-minibuffer
           (format "Set bookmark (%s): " default)
	   nil
	   (let ((now-map (copy-keymap minibuffer-local-map)))
	     (progn (define-key now-map  "\C-w" 
		      'bookmark-yank-word)
		    (define-key now-map  "\C-v" 
		      'bookmark-insert-current-file-name)
		    (define-key now-map  "\C-u" 
		      'bookmark-insert-current-bookmark))
	     now-map))))
    (and (string-equal str "") (setq str default))  
Richard M. Stallman's avatar
Richard M. Stallman committed
271 272
    (progn
      (bookmark-make parg str)
273 274 275 276 277
      (setq bookmark-current-bookmark str)
      (if (get-buffer "*Bookmark List*") ;rebuild the bookmark list
          (save-excursion
            (save-window-excursion 
              (list-bookmarks))))
Richard M. Stallman's avatar
Richard M. Stallman committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
      (goto-char bookmark-current-point))))

(defun bookmark-insert-current-bookmark ()
  ;; insert this buffer's value of bookmark-current-bookmark, default
  ;; to file name if it's nil.
  (interactive)
  (let ((str
	 (save-excursion
	   (set-buffer bookmark-current-buffer)
	   bookmark-current-bookmark)))
    (if str (insert str) (bookmark-insert-current-file-name))))

(defun bookmark-insert-current-file-name ()
  ;; insert the name (sans path) of the current file into the bookmark
  ;; name that is being set.
  (interactive)
  (let ((str (save-excursion
295 296
                 (set-buffer bookmark-current-buffer)
                 (bookmark-buffer-file-name))))
Richard M. Stallman's avatar
Richard M. Stallman committed
297 298 299 300 301 302 303 304 305 306 307
    (insert (substring 
	     str
	     (1+ (string-match 
		  "\\(/[^/]*\\)/*$"
		  str))))))

(defun bookmark-yank-word ()
  (interactive)
  ;; get the next word from the buffer and append it to the name of
  ;; the bookmark currently being set.
  (let ((string (save-excursion
308 309 310 311 312 313 314
                    (set-buffer bookmark-current-buffer)
                    (goto-char bookmark-yank-point)
                    (buffer-substring
                     (point)
                     (save-excursion
                       (forward-word 1)
                       (setq bookmark-yank-point (point)))))))
Richard M. Stallman's avatar
Richard M. Stallman committed
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    (insert string)))

(defun bookmark-make (parg str)
  (if (and (assoc str bookmark-alist) (not parg))
      ;; already existing boookmark under that name and
      ;; no prefix arg means just overwrite old bookmark
      (setcdr (assoc str bookmark-alist)
              (list (bookmark-make-cell)))
    
    ;; otherwise just cons it onto the front (either the bookmark
    ;; doesn't exist already, or there is no prefix arg.  In either
    ;; case, we want the new bookmark consed onto the alist...)
    
    (setq bookmark-alist
          (cons
           (list str 
                 (bookmark-make-cell))
           bookmark-alist)))
  ;; Added by db
  (setq bookmark-current-bookmark str)
  (setq bookmark-alist-modification-count
        (1+ bookmark-alist-modification-count))
  (if (bookmark-time-to-save-p)
      (bookmark-save)))

(defun bookmark-make-cell ()
  ;; make the cell that is the cdr of a bookmark alist element.  It
  ;; looks like this:
  ;; (filename search-forward-str search-back-str point)
  (list
   (bookmark-buffer-file-name)
   (if (>= (- (point-max) (point)) bookmark-search-size)
       (buffer-substring 
        (point)
        (+ (point) bookmark-search-size))
     nil)
   (if (>= (- (point) (point-min)) bookmark-search-size)
       (buffer-substring 
        (point)
        (- (point) bookmark-search-size))
     nil)
   (point)))

(defun bookmark-buffer-file-name ()
  (or
   buffer-file-name
   (if (and (boundp 'dired-directory) dired-directory)
       (if (stringp dired-directory)
	   dired-directory
	 (car dired-directory)))))

(defun bookmark-try-default-file ()
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
  (and (not bookmarks-already-loaded)
       (null bookmark-alist)
       (file-readable-p (expand-file-name bookmark-file))
       (progn
         (bookmark-load bookmark-file t t)
         (setq bookmarks-already-loaded t))))

(defun bookmark-maybe-sort-alist ()
  ;;Return the bookmark-alist for display.  If the bookmark-sort-flag
  ;;is non-nil, then return a sorted copy of the alist.
  (if bookmark-sort-flag
      (setq bookmark-alist
            (sort (copy-alist bookmark-alist)
                  (function
                   (lambda (x y) (string-lessp (car x) (car y))))))))

;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
384
(defun bookmark-jump (str)
Richard M. Stallman's avatar
Richard M. Stallman committed
385 386 387 388
  "Jump to bookmark BOOKMARK (a point in some file).  
You may have a problem using this function if the value of variable
`bookmark-alist' is nil.  If that happens, you need to load in some
bookmarks.  See help on function `bookmark-load' for more about
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
this.

If the file pointed to by BOOKMARK no longer exists, you will be asked
if you wish to give the bookmark a new location, and bookmark-jump
will then jump to the new location, as well as recording it in place
of the old one in the permanent bookmark record."
  (interactive (progn (bookmark-try-default-file)
                      (let* ((completion-ignore-case
                              bookmark-completion-ignore-case)
                             (default 
                               (or (and 
                                    (assoc bookmark-current-bookmark
                                           bookmark-alist)
                                    bookmark-current-bookmark)
                                   (and (assoc (buffer-name (current-buffer))
                                               bookmark-alist)
                                        (buffer-name (current-buffer)))))
                             (str
                              (completing-read
                               (if default 
                                   (format "Jump to bookmark (%s): "
                                           default)
                                 "Jump to bookmark: ")
                               bookmark-alist
                               nil
                               0)))
                        (and (string-equal "" str)
                             (setq str default))
                        (list str))))
  (let ((cell (bookmark-jump-noselect str)))
    (and cell
         (switch-to-buffer (car cell))
         (goto-char (cdr cell)))))

(defun bookmark-jump-noselect (str)
  ;; a leetle helper for bookmark-jump :-)
  ;; returns (BUFFER . POINT)
  (let ((whereto-list (car (cdr (assoc str bookmark-alist)))))
    (let* ((file (expand-file-name (car whereto-list)))
           (orig-file file)
           (forward-str (car (cdr whereto-list)))
           (behind-str (car (cdr (cdr whereto-list))))
           (place (car (cdr (cdr (cdr whereto-list))))))
      (if (or
           (file-exists-p file)
           ;; else try some common compression extensions
           ;; and Emacs better handle it right!
           (setq file
                 (or
                  (let ((altname (concat file ".Z")))
                    (and (file-exists-p altname)
                         altname))
                  (let ((altname (concat file ".gz")))
                    (and (file-exists-p altname)
                         altname))
                  (let ((altname (concat file ".z")))
                    (and (file-exists-p altname)
                         altname)))))
          (save-excursion
            (set-buffer (find-file-noselect file))
            (goto-char place)
            ;; Go searching forward first.  Then, if forward-str exists and
            ;; was found in the file, we can search backward for behind-str.
            ;; Rationale is that if text was inserted between the two in the
            ;; file, it's better to be put before it so you can read it,
            ;; rather than after and remain perhaps unaware of the changes.
            (if forward-str
                (if (search-forward forward-str (point-max) t)
                    (backward-char bookmark-search-size)))
            (if behind-str
                (if (search-backward behind-str (point-min) t)
                    (forward-char bookmark-search-size)))
            ;; added by db
            (setq bookmark-current-bookmark str)
            (cons (current-buffer) (point)))
        (progn
          (ding)
          (if (y-or-n-p (concat (file-name-nondirectory orig-file)
                                " nonexistent.  Relocate \""
                                str
                                "\"? "))
              (progn
                (bookmark-relocate str)
                ;; gasp!  It's a recursive function call in Emacs Lisp!
                (bookmark-jump-noselect str))
            (message 
             "Bookmark not relocated, but deleting it would be a good idea.")
            nil))))))

;;;###autoload
(defun bookmark-relocate (str)
  "Relocate BOOKMARK -- prompts for a filename, and makes an already
existing bookmark point to that file, instead of the one it used to
point at.  Useful when a file has been renamed after a bookmark was
set in it."
Richard M. Stallman's avatar
Richard M. Stallman committed
484 485
  (interactive (let ((completion-ignore-case
                      bookmark-completion-ignore-case))
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
                 (progn (bookmark-try-default-file)
                        (list (completing-read
                               "Bookmark to relocate: "
                               bookmark-alist
                               nil
                               0)))))
  (let* ((bmrk (assoc str bookmark-alist))
         (bmrk-filename (car (car (cdr bmrk))))
         (newloc (expand-file-name
                 (read-file-name
                  (format "Relocate %s to: " str)
                  (file-name-directory bmrk-filename)))))
    (setcar (car (cdr bmrk)) newloc)))

;;;###autoload
(defun bookmark-locate (str &optional no-insertion)
  "Insert the name of the file associated with BOOKMARK.
Optional second arg NO-INSERTION means merely return the filename as a
string."
  (interactive (let ((completion-ignore-case
                      bookmark-completion-ignore-case))
                 (progn (bookmark-try-default-file)
                        (list (completing-read
                               "Insert bookmark location: "
                               bookmark-alist
                               nil
                               0)))))
  (let ((where (car (car (cdr (assoc str bookmark-alist))))))
    (if no-insertion
        where
      (insert where))))

;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
519
(defun bookmark-rename (old &optional new)
520 521 522 523 524 525 526
  "Change the name of OLD-BOOKMARK to NEWNAME.  
If called from keyboard, prompts for OLD-BOOKMARK and NEWNAME.
If called from menubar, OLD-BOOKMARK is selected from a menu, and
prompts for NEWNAME. 
If called from Lisp, prompts for NEWNAME if only OLD-BOOKMARK was
passed as an argument.  If called with two strings, then no prompting
is done.  You must pass at least OLD-BOOKMARK when calling from Lisp.
Richard M. Stallman's avatar
Richard M. Stallman committed
527 528 529 530

While you are entering the new name, consecutive C-w's insert
consectutive words from the text of the buffer into the new bookmark
name, and C-v inserts the name of the file."
Richard M. Stallman's avatar
Richard M. Stallman committed
531 532
  (interactive (let ((completion-ignore-case
                      bookmark-completion-ignore-case))
533 534 535 536 537
                 (progn (bookmark-try-default-file)
                        (list (completing-read "Old bookmark name: "
                                               bookmark-alist
                                               nil
                                               0)))))
Richard M. Stallman's avatar
Richard M. Stallman committed
538 539 540 541 542 543
  (progn
    (setq bookmark-current-point (point))
    (setq bookmark-yank-point (point))
    (setq bookmark-current-buffer (current-buffer))
    (let ((cell (assoc old bookmark-alist))
	  (str
Richard M. Stallman's avatar
Richard M. Stallman committed
544 545 546 547 548 549 550 551 552 553
           (or new   ; use second arg, if non-nil
               (read-from-minibuffer 
                "New name: "
                nil
                (let ((now-map (copy-keymap minibuffer-local-map)))
                  (progn (define-key now-map  "\C-w" 
                           'bookmark-yank-word)
                         (define-key now-map  "\C-v" 
                           'bookmark-insert-current-file-name))
                  now-map)))))
Richard M. Stallman's avatar
Richard M. Stallman committed
554 555 556
      (progn
	(setcar cell str)
	(setq bookmark-current-bookmark str)
557 558
        (if (get-buffer "*Bookmark List*")
            (save-excursion (save-window-excursion (list-bookmarks))))
Richard M. Stallman's avatar
Richard M. Stallman committed
559 560 561 562 563
	(setq bookmark-alist-modification-count
	      (1+ bookmark-alist-modification-count))
	(if (bookmark-time-to-save-p)
	    (bookmark-save))))))

564
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
565
(defun bookmark-insert (str)
Richard M. Stallman's avatar
Richard M. Stallman committed
566 567 568 569
  "Insert the text of the file pointed to by bookmark BOOKMARK.  
You may have a problem using this function if the value of variable
`bookmark-alist' is nil.  If that happens, you need to load in some
bookmarks.  See help on function `bookmark-load' for more about
Richard M. Stallman's avatar
Richard M. Stallman committed
570
this."
Richard M. Stallman's avatar
Richard M. Stallman committed
571 572
  (interactive (let ((completion-ignore-case
                      bookmark-completion-ignore-case))
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
                 (progn (bookmark-try-default-file)
                        (list (completing-read
                               "Insert bookmark contents: "
                               bookmark-alist
                               nil
                               0)))))
  (let ((orig-point (point))
        (str-to-insert
         (save-excursion
           (set-buffer (car (bookmark-jump-noselect str)))
           (buffer-substring (point-min) (point-max)))))
    (insert str-to-insert)
    (push-mark)
    (goto-char orig-point)))

;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
589
(defun bookmark-delete (str)
Richard M. Stallman's avatar
Richard M. Stallman committed
590 591 592 593 594
  "Delete the bookmark named NAME from the bookmark list.  
Removes only the first instance of a bookmark with that name.  If
there are one or more other bookmarks with the same name, they will
not be deleted.  Defaults to the \"current\" bookmark \(that is, the
one most recently used in this file, if any\)."
Richard M. Stallman's avatar
Richard M. Stallman committed
595 596
  (interactive (let ((completion-ignore-case
		      bookmark-completion-ignore-case))
597 598 599 600 601 602 603 604
		 (progn (bookmark-try-default-file)
                        (list
                         (completing-read
                          "Delete bookmark: "
                          bookmark-alist
                          nil
                          0
                          bookmark-current-bookmark)))))
Richard M. Stallman's avatar
Richard M. Stallman committed
605 606 607 608
  (let ((will-go (assoc str bookmark-alist)))
    (setq bookmark-alist (delq will-go bookmark-alist))
    ;; Added by db, nil bookmark-current-bookmark if the last
    ;; occurence has been deleted
Richard M. Stallman's avatar
Richard M. Stallman committed
609
    (or (assoc bookmark-current-bookmark bookmark-alist)
Richard M. Stallman's avatar
Richard M. Stallman committed
610
        (setq bookmark-current-bookmark nil)))
611 612
  (if (get-buffer "*Bookmark List*")
      (save-excursion (save-window-excursion (list-bookmarks))))
Richard M. Stallman's avatar
Richard M. Stallman committed
613 614 615 616
  (setq bookmark-alist-modification-count
        (1+ bookmark-alist-modification-count))
  (if (bookmark-time-to-save-p)
      (bookmark-save)))
Richard M. Stallman's avatar
Richard M. Stallman committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632

(defun bookmark-time-to-save-p (&optional last-time)
  ;; By Gregory M. Saunders <saunders@cis.ohio-state.edu>
  ;; finds out whether it's time to save bookmarks to a file, by
  ;; examining the value of variable bookmark-save-flag, and maybe
  ;; bookmark-alist-modification-count.  Returns t if they should be
  ;; saved, nil otherwise.  if last-time is non-nil, then this is
  ;; being called when emacs is killed.
  (cond (last-time 
	 (and (> bookmark-alist-modification-count 0)
	      bookmark-save-flag))
	((numberp bookmark-save-flag)
	 (>= bookmark-alist-modification-count bookmark-save-flag))
	(t
	 nil)))

633
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
634
(defun bookmark-write ()
635 636 637
  "Write bookmarks to a file \(for which the user will be prompted
interactively\).  Don't use this in Lisp programs; use bookmark-save
instead."
Richard M. Stallman's avatar
Richard M. Stallman committed
638
  (interactive)
639
  (bookmark-try-default-file)
Richard M. Stallman's avatar
Richard M. Stallman committed
640 641
  (bookmark-save t))

642
;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
643
(defun bookmark-save (&optional parg file) 
Richard M. Stallman's avatar
Richard M. Stallman committed
644 645 646
  "Save currently defined bookmarks.
Saves by default in the file defined by the variable
`bookmark-file'.  With a prefix arg, save it in file FILE.
Richard M. Stallman's avatar
Richard M. Stallman committed
647 648 649 650 651 652 653

If you are calling this from Lisp, the two arguments are PREFIX-ARG
and FILE, and if you just want it to write to the default file, then
pass no arguments.  Or pass in nil and FILE, and it will save in FILE
instead.  If you pass in one argument, and it is non-nil, then the
user will be interactively queried for a file to save in.

Richard M. Stallman's avatar
Richard M. Stallman committed
654
When you want to load in the bookmarks from a file, use
Richard M. Stallman's avatar
Richard M. Stallman committed
655
\`bookmark-load\', \\[bookmark-load].  That function will prompt you
Richard M. Stallman's avatar
Richard M. Stallman committed
656
for a file, defaulting to the file defined by variable
Richard M. Stallman's avatar
Richard M. Stallman committed
657
`bookmark-file'."
Richard M. Stallman's avatar
Richard M. Stallman committed
658
  (interactive "P")
659
  (bookmark-try-default-file)
Richard M. Stallman's avatar
Richard M. Stallman committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
  (cond
   ((and (null parg) (null file))
    ;;whether interactive or not, write to default file
    (bookmark-write-file bookmark-file))
   ((and (null parg) file)
    ;;whether interactive or not, write to given file
    (bookmark-write-file file))
   ((and parg (not file))
    ;;have been called interactively w/ prefix arg
    (let ((file (read-file-name "File to save bookmarks in: ")))
      (bookmark-write-file file)))
   (t ; someone called us with prefix-arg *and* a file, so just write to file
    (bookmark-write-file file)))
  ;; signal that we have synced the bookmark file by setting this to
  ;; 0.  If there was an error at any point before, it will not get
  ;; set, which is what we want.
  (setq bookmark-alist-modification-count 0))

(defun bookmark-write-file (file)
  (save-excursion
680 681 682
    (save-window-excursion
      (if (>= baud-rate 9600)
          (message (format "Saving bookmarks to file %s." file)))
Karl Fogel's avatar
Karl Fogel committed
683 684
      (set-buffer (let ((enable-local-eval nil))
                    (find-file-noselect file)))
685 686 687 688 689 690 691 692 693 694 695 696 697 698
      (goto-char (point-min))
      (delete-region (point-min) (point-max))
      (print bookmark-alist (current-buffer))
      (let ((version-control
             (cond
              ((null bookmark-version-control) nil)
              ((eq 'never bookmark-version-control) 'never)
              ((eq 'nospecial bookmark-version-control) version-control)
              (t
               t))))
        (write-file file)
        (kill-buffer (current-buffer))))))

;;;###autoload
Richard M. Stallman's avatar
Richard M. Stallman committed
699
(defun bookmark-load (file &optional revert no-msg)
Richard M. Stallman's avatar
Richard M. Stallman committed
700 701 702 703 704
  "Load bookmarks from FILE (which must be in bookmark format).
Appends loaded bookmarks to the front of the list of bookmarks.  If
optional second argument REVERT is non-nil, existing bookmarks are
destroyed.  Optional third arg NO-MSG means don't display any messages
while loading.
Richard M. Stallman's avatar
Richard M. Stallman committed
705 706

If you load a file that doesn't contain a proper bookmark alist, you
Richard M. Stallman's avatar
Richard M. Stallman committed
707
will corrupt Emacs's bookmark list.  Generally, you should only load
Richard M. Stallman's avatar
Richard M. Stallman committed
708
in files that were created with the bookmark functions in the first
Richard M. Stallman's avatar
Richard M. Stallman committed
709
place.  Your own personal bookmark file, `~/.emacs-bkmrks', is
Richard M. Stallman's avatar
Richard M. Stallman committed
710
maintained automatically by Emacs; you shouldn't need to load it
Richard M. Stallman's avatar
Richard M. Stallman committed
711
explicitly."
Richard M. Stallman's avatar
Richard M. Stallman committed
712
  (interactive
713 714 715 716 717 718 719 720
   (progn (bookmark-try-default-file)
          (list (read-file-name
                 (format "Load bookmarks from: (%s) "
                         bookmark-file)        
                 ;;Default might not be used often,
                 ;;but there's no better default, and
                 ;;I guess it's better than none at all.
                 "~/" bookmark-file 'confirm))))
Richard M. Stallman's avatar
Richard M. Stallman committed
721 722 723
  (setq file (expand-file-name file))
  (if (file-readable-p file)
      (save-excursion
724 725 726
        (save-window-excursion
          (if (and (null no-msg) (>= baud-rate 9600))
              (message (format "Loading bookmarks from %s..." file)))
Karl Fogel's avatar
Karl Fogel committed
727 728
          (set-buffer (let ((enable-local-eval nil))
                        (find-file-noselect file)))
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
          (goto-char (point-min))
          (let ((blist (car (read-from-string
                             (buffer-substring (point-min) (point-max))))))
            (if (listp blist)
                (progn
                  (if (not revert)
                      (setq bookmark-alist-modification-count
                            (1+ bookmark-alist-modification-count))
                    (setq bookmark-alist-modification-count 0))
                  (setq bookmark-alist
                        (append blist (if (not revert) bookmark-alist)))
                  (if (get-buffer "*Bookmark List*") 
                      (save-excursion (list-bookmarks)))) 
              (error (format "Invalid bookmark list in %s." file))))
          (kill-buffer (current-buffer)))
	(if (and (null no-msg) (>= baud-rate 9600))
            (message (format "Loading bookmarks from %s... done" file))))
Richard M. Stallman's avatar
Richard M. Stallman committed
746 747
    (error (format "Cannot read bookmark file %s." file))))

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159
;;;; bookmark-menu-mode stuff ;;;;

(defvar Bookmark-menu-bookmark-column nil)

(defvar Bookmark-menu-hidden-bookmarks ())

(defvar Bookmark-menu-file-column 30
  "*Column at which to display filenames in a buffer listing bookmarks.
You can toggle whether files are shown with \\<Bookmark-menu-mode-map>\\[Bookmark-menu-toggle-filenames].")

(defvar Bookmark-menu-toggle-filenames t
  "*Non-nil means show filenames when listing bookmarks.
This may result in truncated bookmark names.  To disable this, put the
following in your .emacs:

\(setq Bookmark-menu-toggle-filenames nil\)")

(defvar Bookmark-menu-mode-map nil)

(if Bookmark-menu-mode-map
    nil
  (setq Bookmark-menu-mode-map (make-keymap))
  (suppress-keymap Bookmark-menu-mode-map t)
  (define-key Bookmark-menu-mode-map "q" 'Bookmark-menu-quit)
  (define-key Bookmark-menu-mode-map "v" 'Bookmark-menu-select)
  (define-key Bookmark-menu-mode-map "w" 'Bookmark-menu-locate)
  (define-key Bookmark-menu-mode-map "2" 'Bookmark-menu-2-window)
  (define-key Bookmark-menu-mode-map "1" 'Bookmark-menu-1-window)
  (define-key Bookmark-menu-mode-map "j" 'Bookmark-menu-this-window)
  (define-key Bookmark-menu-mode-map "f" 'Bookmark-menu-this-window)
  (define-key Bookmark-menu-mode-map "o" 'Bookmark-menu-other-window)
  (define-key Bookmark-menu-mode-map "\C-o" 'Bookmark-menu-switch-other-window)
  (define-key Bookmark-menu-mode-map "s" 'Bookmark-menu-save)
  (define-key Bookmark-menu-mode-map "k" 'Bookmark-menu-delete)
  (define-key Bookmark-menu-mode-map "\C-d" 'Bookmark-menu-delete-backwards)
  (define-key Bookmark-menu-mode-map "x" 'Bookmark-menu-execute)
  (define-key Bookmark-menu-mode-map "\C-k" 'Bookmark-menu-delete)
  (define-key Bookmark-menu-mode-map "d" 'Bookmark-menu-delete)
  (define-key Bookmark-menu-mode-map " " 'next-line)
  (define-key Bookmark-menu-mode-map "n" 'next-line)
  (define-key Bookmark-menu-mode-map "p" 'previous-line)
  (define-key Bookmark-menu-mode-map "\177" 'Bookmark-menu-backup-unmark)
  (define-key Bookmark-menu-mode-map "?" 'describe-mode)
  (define-key Bookmark-menu-mode-map "u" 'Bookmark-menu-unmark)
  (define-key Bookmark-menu-mode-map "m" 'Bookmark-menu-mark)
  (define-key Bookmark-menu-mode-map "l" 'Bookmark-menu-load) 
  (define-key Bookmark-menu-mode-map "r" 'Bookmark-menu-rename)
  (define-key Bookmark-menu-mode-map "t" 'Bookmark-menu-toggle-filenames))

;; Bookmark Menu mode is suitable only for specially formatted data.
(put 'Bookmark-menu-mode 'mode-class 'special)

;; need to display whether or not bookmark exists as a buffer in flag
;; column. 

;; Format:
;; FLAGS  BOOKMARK (/FILE/NAME/HERE/WHAT/REGEXP/TO/USE?)
;; goto bookmark-column and then search till "(/[^)]*)$" or "(/.*)$" ? 

;;;###autoload
(defalias 'edit-bookmarks 'list-bookmarks)

;;;###autoload
(defun list-bookmarks ()
  "Display a list of existing bookmarks.
The list is displayed in a buffer named `*Bookmark List*'.
The leftmost column displays a D if the bookmark is flagged for
deletion, or > if it is flagged for displaying."
  (interactive)
  (bookmark-try-default-file)
  (switch-to-buffer (get-buffer-create "*Bookmark List*"))
  (let ((buffer-read-only nil))
    (delete-region (point-max) (point-min))
    (goto-char (point-min)) ;sure are playing it safe...
    (insert "% Bookmark\n- --------\n")
    (bookmark-maybe-sort-alist)
    (let ((lst bookmark-alist))
      (while lst
        (insert
         (concat "  " (car (car lst)) "\n"))
        (setq lst (cdr lst)))))
  (goto-char (point-min))
  (forward-line 2)
  (bookmark-menu-mode)
  (if Bookmark-menu-toggle-filenames
      (Bookmark-menu-toggle-filenames t)))

(defun bookmark-menu-mode ()
  "Major mode for editing a list of bookmarks.
Each line describes one of the bookmarks in Emacs.
Letters do not insert themselves; instead, they are commands.
\\<Bookmark-menu-mode-map>
\\[Bookmark-menu-mark] -- mark bookmark to be displayed.
\\[Bookmark-menu-select] -- select bookmark of line point is on.
  Also show bookmarks marked using m in other windows.
\\[Bookmark-menu-toggle-filenames] -- toggle displaying of filenames (they may obscure long bookmark names).
\\[Bookmark-menu-locate] -- display (in minibuffer) location of this bookmark.
\\[Bookmark-menu-1-window] -- select this bookmark in full-frame window.
\\[Bookmark-menu-2-window] -- select this bookmark in one window,
  together with bookmark selected before this one in another window.
\\[Bookmark-menu-this-window] -- select this bookmark in place of the bookmark menu buffer.
\\[Bookmark-menu-other-window] -- select this bookmark in another window,
  so the bookmark menu bookmark remains visible in its window.
\\[Bookmark-menu-switch-other-window] -- switch the other window to this bookmark.
\\[Bookmark-menu-rename] -- rename this bookmark \(prompts for new name\).   
\\[Bookmark-menu-delete] -- mark this bookmark to be deleted, and move down.
\\[Bookmark-menu-delete-backwards] -- mark this bookmark to be deleted, and move up. 
\\[Bookmark-menu-execute] -- delete marked bookmarks.
\\[Bookmark-menu-save] -- save the current bookmark list in the default file.
  With a prefix arg, prompts for a file to save in.
\\[Bookmark-menu-load] -- load in a file of bookmarks (prompts for file.)
\\[Bookmark-menu-unmark] -- remove all kinds of marks from current line.
  With prefix argument, also move up one line.
\\[Bookmark-menu-backup-unmark] -- back up a line and remove marks."
  (kill-all-local-variables)
  (use-local-map Bookmark-menu-mode-map)
  (setq truncate-lines t)
  (setq buffer-read-only t)
  (setq major-mode 'bookmark-menu-mode)
  (setq mode-name "Bookmark Menu")
  (run-hooks 'bookmark-menu-mode-hook))

(defun Bookmark-menu-toggle-filenames (&optional parg)
  "Toggle whether filenames are shown in the bookmark list.
Optional argument SHOW means show them unconditionally."
  (interactive)
  (cond
   (parg
    (setq Bookmark-menu-toggle-filenames nil)
    (Bookmark-menu-show-filenames)
    (setq Bookmark-menu-toggle-filenames t))
   (Bookmark-menu-toggle-filenames
    (Bookmark-menu-hide-filenames)
    (setq Bookmark-menu-toggle-filenames nil))
   (t
    (Bookmark-menu-show-filenames)
    (setq Bookmark-menu-toggle-filenames t))))

(defun Bookmark-menu-show-filenames (&optional force)
  (if (and (not force) Bookmark-menu-toggle-filenames)
      nil ;already shown, so do nothing
    (save-excursion
      (save-window-excursion
        (goto-char (point-min))
        (forward-line 2)
        (setq Bookmark-menu-hidden-bookmarks ())
        (let ((buffer-read-only nil))
          (while (< (point) (point-max))
            (let ((bmrk (Bookmark-menu-bookmark)))
              (setq Bookmark-menu-hidden-bookmarks
                    (cons bmrk Bookmark-menu-hidden-bookmarks))
              (move-to-column Bookmark-menu-file-column t)
              (delete-region (point) (progn (end-of-line) (point)))
              (insert "  ")
              (bookmark-locate bmrk)
              (forward-line 1))))))))

(defun Bookmark-menu-hide-filenames (&optional force)
  (if (and (not force) Bookmark-menu-toggle-filenames)
      ;; nothing to hide if above is nil
      (save-excursion
        (save-window-excursion
          (goto-char (point-min))
          (forward-line 2)
          (setq Bookmark-menu-hidden-bookmarks
                (nreverse Bookmark-menu-hidden-bookmarks))
          (save-excursion
            (goto-char (point-min))
            (search-forward "Bookmark")
            (backward-word 1)
            (setq Bookmark-menu-bookmark-column (current-column)))
          (save-excursion
            (let ((buffer-read-only nil))
              (while Bookmark-menu-hidden-bookmarks
                (move-to-column Bookmark-menu-bookmark-column t)
                (kill-line)
                (insert (car Bookmark-menu-hidden-bookmarks))
                (setq Bookmark-menu-hidden-bookmarks
                      (cdr Bookmark-menu-hidden-bookmarks))
                (forward-line 1))))))))

;; if you look at this next function from far away, it resembles a
;; gun.  But only with this comment above... 
(defun Bookmark-menu-check-position ()
  ;; Returns t if on a line with a bookmark.
  ;; Otherwise, repositions and returns t.
  ;; written by David Hughes <djh@harston.cv.com>
  ;; Mucho thanks, David!  -karl
  (cond ((< (count-lines (point-min) (point)) 2)
         (goto-char (point-min))
         (forward-line 2)
         t)
        ((and (bolp) (eobp))
         (beginning-of-line 0)
         t)
        (t
         t)))

(defun Bookmark-menu-bookmark ()
  ;; return a string which is bookmark of this line.
  (if (Bookmark-menu-check-position)
      (save-excursion
        (save-window-excursion
          (goto-char (point-min))
          (search-forward "Bookmark")
          (backward-word 1)
          (setq Bookmark-menu-bookmark-column (current-column)))))
  (if Bookmark-menu-toggle-filenames
      (Bookmark-menu-hide-filenames))
  (save-excursion
    (save-window-excursion
      (beginning-of-line)
      (forward-char Bookmark-menu-bookmark-column)
      (prog1
          (buffer-substring (point)
                            (progn 
                              (end-of-line)
                              (point)))
        ;; well, this is certainly crystal-clear:
        (if Bookmark-menu-toggle-filenames
            (Bookmark-menu-toggle-filenames t))))))

(defun Bookmark-menu-mark ()
  "Mark bookmark on this line to be displayed by \\<Bookmark-menu-mode-map>\\[Bookmark-menu-select] command."
  (interactive)
  (beginning-of-line)
  (if (Bookmark-menu-check-position)
      (let ((buffer-read-only nil))
        (delete-char 1)
        (insert ?>)
        (forward-line 1))))

(defun Bookmark-menu-select ()
  "Select this line's bookmark; also display bookmarks marked with `>'.
You can mark bookmarks with the \\<Bookmark-menu-mode-map>\\[Bookmark-menu-mark] command."
  (interactive)
  (if (Bookmark-menu-check-position)
      (let ((bmrk (Bookmark-menu-bookmark))
            (menu (current-buffer))	      
            (others ())
            tem)
        (goto-char (point-min))
        (while (re-search-forward "^>" nil t)
          (setq tem (Bookmark-menu-bookmark))
          (let ((buffer-read-only nil))
            (delete-char -1)
            (insert ?\ ))
          (or (string-equal tem bmrk) 
              (memq tem others) 
              (setq others (cons tem others))))
        (setq others (nreverse others)
              tem (/ (1- (frame-height)) (1+ (length others))))
        (delete-other-windows)
        (bookmark-jump bmrk)
        (bury-buffer menu)
        (if (equal (length others) 0)
            nil
          (while others
            (split-window nil tem)
            (other-window 1)
            (bookmark-jump (car others))
            (setq others (cdr others)))
          (other-window 1)))))

(defun Bookmark-menu-save (parg)
  "Save the current list into a bookmark file.
With a prefix arg, prompts for a file to save them in."
  (interactive "P")
  (save-excursion
    (save-window-excursion
      (bookmark-save parg))))

(defun Bookmark-menu-load ()
  "Load a bookmark file and rebuild list."
  (interactive)
  (if (Bookmark-menu-check-position)
      (save-excursion
        (save-window-excursion
          (call-interactively 'bookmark-load)))))

(defun Bookmark-menu-1-window ()
  "Select this line's bookmark, alone, in full frame."
  (interactive)
  (if (Bookmark-menu-check-position)
      (progn
        (bookmark-jump (Bookmark-menu-bookmark))
        (bury-buffer (other-buffer))
        (delete-other-windows))))

(defun Bookmark-menu-2-window ()
  "Select this line's bookmark, with previous buffer in second window."
  (interactive)
  (if (Bookmark-menu-check-position)
      (let ((bmrk (Bookmark-menu-bookmark))
            (menu (current-buffer))
            (pop-up-windows t))
        (delete-other-windows)
        (switch-to-buffer (other-buffer))
        (let ((buff (car (bookmark-jump-noselect bmrk))))
          (pop-to-buffer buff))
        (bury-buffer menu))))

(defun Bookmark-menu-this-window ()
  "Select this line's bookmark in this window."
  (interactive)
  (if (Bookmark-menu-check-position)
      (bookmark-jump (Bookmark-menu-bookmark))))

(defun Bookmark-menu-other-window ()
  "Select this line's bookmark in other window, leaving bookmark menu visible."
  (interactive)
  (if (Bookmark-menu-check-position)
      (let ((buff (car (bookmark-jump-noselect (Bookmark-menu-bookmark)))))
        (switch-to-buffer-other-window buff))))

(defun Bookmark-menu-switch-other-window ()
  "Make the other window select this line's bookmark.
The current window remains selected."
  (interactive)
  (if (Bookmark-menu-check-position)
      (let ((buff (car (bookmark-jump-noselect (Bookmark-menu-bookmark)))))
        (display-buffer buff))))

(defun Bookmark-menu-quit ()
  "Quit the bookmark menu."
  (interactive)
  (let ((buffer (current-buffer)))
    (switch-to-buffer (other-buffer))
    (bury-buffer buffer)))

(defun Bookmark-menu-unmark (&optional backup)
  "Cancel all requested operations on bookmark on this line and move down.
Optional ARG means move up."
  (interactive "P")
  (beginning-of-line)
  (if (Bookmark-menu-check-position)
      (progn
        (let ((buffer-read-only nil))
          (delete-char 1)
          ;; any flags to reset according to circumstances?  How about a
          ;; flag indicating whether this bookmark is being visited?
          ;; well, we don't have this now, so maybe later.
          (insert " "))
        (forward-line (if backup -1 1)))))

(defun Bookmark-menu-backup-unmark ()
  "Move up and cancel all requested operations on bookmark on line above."
  (interactive)
  (forward-line -1)
  (if (Bookmark-menu-check-position)
      (progn
        (Bookmark-menu-unmark)
        (forward-line -1))))

(defun Bookmark-menu-delete ()
  "Mark bookmark on this line to be deleted by \\<Bookmark-menu-mode-map>\\[Bookmark-menu-execute] command."
  (interactive)
  (beginning-of-line)
  (if (Bookmark-menu-check-position)
      (let ((buffer-read-only nil))
        (delete-char 1)
        (insert ?D)
        (forward-line 1))))

(defun Bookmark-menu-delete-backwards ()
  "Mark bookmark on this line to be deleted by \\<Bookmark-menu-mode-map>\\[Bookmark-menu-execute] command
and then move up one line"
  (interactive)
  (Bookmark-menu-delete)
  (forward-line -2)
  (if (Bookmark-menu-check-position)
      (forward-line 1)))

(defun Bookmark-menu-execute ()
  "Delete bookmarks marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
  (interactive)
  (let ((hide-em Bookmark-menu-toggle-filenames))
    (if hide-em (Bookmark-menu-hide-filenames))
    (setq Bookmark-menu-toggle-filenames nil)
    (goto-char (point-min))
    (forward-line 1)
    (let ((deaders ()))
      (while (re-search-forward "^D" (point-max) t)
        (setq deaders (cons (Bookmark-menu-bookmark) deaders)))
      (mapcar (lambda (str) 
                (setq bookmark-alist 
                      (delq (assoc str bookmark-alist) bookmark-alist)))
              deaders))
    (list-bookmarks)
    (goto-char (point-min))
    (forward-line 2)
    (setq Bookmark-menu-toggle-filenames hide-em)
    (if Bookmark-menu-toggle-filenames
        (Bookmark-menu-toggle-filenames t))))

(defun Bookmark-menu-rename ()
  "Rename bookmark on current line.  Prompts for a new name."
  (interactive)
  (if (Bookmark-menu-check-position)
      (let ((bmrk (Bookmark-menu-bookmark))
            (thispoint (point)))
        (bookmark-rename bmrk)
        (list-bookmarks)
        (goto-char thispoint))))

(defun Bookmark-menu-locate ()
  "Display location of this bookmark.  Displays in the minibuffer."
  (interactive)
  (if (Bookmark-menu-check-position)
      (let ((bmrk (Bookmark-menu-bookmark)))
        (message (bookmark-locate bmrk t)))))

Richard M. Stallman's avatar
Richard M. Stallman committed
1160 1161
;;;; bookmark menu bar stuff ;;;;

1162
(defvar bookmark-menu-bar-length 70
Richard M. Stallman's avatar
Richard M. Stallman committed
1163
  "*Maximum length of a bookmark name displayed on a popup menu.")
Richard M. Stallman's avatar
Richard M. Stallman committed
1164

Richard M. Stallman's avatar
Richard M. Stallman committed
1165
(defun bookmark-make-menu-bar-alist ()
1166 1167
  (bookmark-try-default-file)
  (bookmark-maybe-sort-alist)
Richard M. Stallman's avatar
Richard M. Stallman committed
1168 1169 1170 1171
  (if bookmark-alist
      (mapcar (lambda (cell)
		(let ((str (car cell)))
		  (cons 
Richard M. Stallman's avatar
Richard M. Stallman committed
1172 1173
		   (if (> (length str) bookmark-menu-bar-length)
		       (substring str 0 bookmark-menu-bar-length)
Richard M. Stallman's avatar
Richard M. Stallman committed
1174 1175 1176 1177 1178
		     str)
		   str)))
	      bookmark-alist)
    (error "No bookmarks currently set.")))

Richard M. Stallman's avatar
Richard M. Stallman committed
1179 1180 1181
(defun bookmark-make-menu-bar-with-function (func-sym 
                                             menu-label
                                             menu-str event) 
Richard M. Stallman's avatar
Richard M. Stallman committed
1182 1183
  ;; help function for making menus that need to apply a bookmark
  ;; function to a string.
Richard M. Stallman's avatar
Richard M. Stallman committed
1184
  (let* ((menu (bookmark-make-menu-bar-alist))
Richard M. Stallman's avatar
Richard M. Stallman committed
1185 1186
	 (str (x-popup-menu event
			    (list menu-label
1187 1188
                                  (cons menu-str menu)))))
    (if str (apply func-sym (list str)))))
Richard M. Stallman's avatar
Richard M. Stallman committed
1189

Richard M. Stallman's avatar
Richard M. Stallman committed
1190
(defun bookmark-menu-bar-insert (event)
Richard M. Stallman's avatar
Richard M. Stallman committed
1191 1192 1193 1194 1195
  "Insert the text of the file pointed to by bookmark BOOKMARK.  
You may have a problem using this function if the value of variable
`bookmark-alist' is nil.  If that happens, you need to load in some
bookmarks.  See help on function `bookmark-load' for more about
this."
Richard M. Stallman's avatar
Richard M. Stallman committed
1196
  (interactive "e")
Richard M. Stallman's avatar
Richard M. Stallman committed
1197
  (bookmark-make-menu-bar-with-function 'bookmark-insert
1198 1199 1200
                                        "Bookmark Insert Menu"
                                        "--- Insert Contents ---"
                                        event))
Richard M. Stallman's avatar
Richard M. Stallman committed
1201

Richard M. Stallman's avatar
Richard M. Stallman committed
1202
(defun bookmark-menu-bar-jump (event)
Richard M. Stallman's avatar
Richard M. Stallman committed
1203 1204 1205 1206 1207
  "Jump to bookmark BOOKMARK (a point in some file).  
You may have a problem using this function if the value of variable
`bookmark-alist' is nil.  If that happens, you need to load in some
bookmarks.  See help on function `bookmark-load' for more about
this."
Richard M. Stallman's avatar
Richard M. Stallman committed
1208
  (interactive "e")
Richard M. Stallman's avatar
Richard M. Stallman committed
1209
  (bookmark-make-menu-bar-with-function 'bookmark-jump
1210 1211 1212
                                        "Bookmark Jump Menu"
                                        "--- Jump to Bookmark ---"
                                        event))
Richard M. Stallman's avatar
Richard M. Stallman committed
1213

Richard M. Stallman's avatar
Richard M. Stallman committed
1214
(defun bookmark-menu-bar-locate (event)
Richard M. Stallman's avatar
Richard M. Stallman committed
1215 1216
  "Insert the name of the  file associated with BOOKMARK. 
\(This is not the same as the contents of that file\)."
Richard M. Stallman's avatar
Richard M. Stallman committed
1217
  (interactive "e")
Richard M. Stallman's avatar
Richard M. Stallman committed
1218
  (bookmark-make-menu-bar-with-function 'bookmark-locate
1219 1220 1221
                                        "Bookmark Locate Menu"
                                        "--- Insert Location ---"
                                        event))
Richard M. Stallman's avatar
Richard M. Stallman committed
1222

Richard M. Stallman's avatar
Richard M. Stallman committed
1223
(defun bookmark-menu-bar-rename (event)
1224 1225 1226 1227 1228 1229 1230
  "Change the name of OLD-BOOKMARK to NEWNAME.  
If called from keyboard, prompts for OLD-BOOKMARK and NEWNAME.
If called from menubar, OLD-BOOKMARK is selected from a menu, and
prompts for NEWNAME. 
If called from Lisp, prompts for NEWNAME if only OLD-BOOKMARK was
passed as an argument.  If called with two strings, then no prompting
is done.  You must pass at least OLD-BOOKMARK when calling from Lisp.
Richard M. Stallman's avatar
Richard M. Stallman committed
1231 1232 1233 1234

While you are entering the new name, consecutive C-w's insert
consectutive words from the text of the buffer into the new bookmark
name, and C-v inserts the name of the file."
Richard M. Stallman's avatar
Richard M. Stallman committed
1235
  (interactive "e")
Richard M. Stallman's avatar
Richard M. Stallman committed
1236
  (bookmark-make-menu-bar-with-function 'bookmark-rename
1237 1238 1239
                                        "Bookmark Rename Menu"
                                        "--- Rename Bookmark ---"
                                        event))
Richard M. Stallman's avatar
Richard M. Stallman committed
1240

Richard M. Stallman's avatar
Richard M. Stallman committed
1241
(defun bookmark-menu-bar-delete (event)
Richard M. Stallman's avatar
Richard M. Stallman committed
1242 1243 1244 1245 1246
  "Delete the bookmark named NAME from the bookmark list.  
Removes only the first instance of a bookmark with that name.  If
there are one or more other bookmarks with the same name, they will
not be deleted.  Defaults to the \"current\" bookmark \(that is, the
one most recently used in this file, if any\)."
Richard M. Stallman's avatar
Richard M. Stallman committed
1247
  (interactive "e")
Richard M. Stallman's avatar
Richard M. Stallman committed
1248
  (bookmark-make-menu-bar-with-function 'bookmark-delete
1249 1250 1251
                                        "Bookmark Delete Menu"
                                        "--- Delete Bookmark ---"
                                        event))
Richard M. Stallman's avatar
Richard M. Stallman committed
1252

1253 1254
;; Thanks to Roland McGrath for fixing menubar.el so that the
;; following works, and for explaining what to do to make it work.
Richard M. Stallman's avatar
Richard M. Stallman committed
1255

1256
(defvar menu-bar-bookmark-map (make-sparse-keymap "Bookmark functions."))
Richard M. Stallman's avatar
Richard M. Stallman committed
1257

1258 1259 1260 1261 1262 1263
;; make bookmarks appear toward the right side of the menu.
(if (boundp 'menu-bar-final-items)
    (if menu-bar-final-items 
        (setq menu-bar-final-items
              (cons 'bookmark menu-bar-final-items)))
  (setq menu-bar-final-items '(bookmark)))
Richard M. Stallman's avatar
Richard M. Stallman committed
1264

1265 1266
(define-key menu-bar-bookmark-map [load]
  '("Load a bookmark file" . bookmark-load))
Richard M. Stallman's avatar
Richard M. Stallman committed
1267

1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
(define-key menu-bar-bookmark-map [write]
  '("Write \(to another file\)" . bookmark-write))

(define-key menu-bar-bookmark-map [save]
  '("Save  \(in default file\)" . bookmark-save))

(define-key menu-bar-bookmark-map [edit]
  '("Edit Bookmark List" . list-bookmarks))

(define-key menu-bar-bookmark-map [delete]
  '("Delete bookmark" . bookmark-menu-bar-delete))

(define-key menu-bar-bookmark-map [rename]
  '("Rename bookmark" . bookmark-menu-bar-rename))

(define-key menu-bar-bookmark-map [locate]
  '("Insert location" . bookmark-menu-bar-locate))
Richard M. Stallman's avatar
Richard M. Stallman committed
1285

1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
(define-key menu-bar-bookmark-map [insert]
  '("Insert contents" . bookmark-menu-bar-insert))

(define-key menu-bar-bookmark-map [set]
  '("Set bookmark" . bookmark-set))

(define-key menu-bar-bookmark-map [jump] 
  '("Jump to bookmark" . bookmark-menu-bar-jump))
 
;;;###autoload (autoload 'menu-bar-bookmark-map "bookmark" nil t 'keymap)

(fset 'menu-bar-bookmark-map (symbol-value 'menu-bar-bookmark-map))

;;;; end bookmark menu-bar stuff ;;;;
Richard M. Stallman's avatar
Richard M. Stallman committed
1300 1301 1302

(provide 'bookmark)
      
Richard M. Stallman's avatar
Richard M. Stallman committed
1303
;;; bookmark.el ends here