* calendar/todos.el: Extend and improve item filtering and handling of
[bpt/emacs.git] / lisp / bookmark.el
index 017eed8..75a8d9f 100644 (file)
@@ -1,7 +1,6 @@
 ;;; bookmark.el --- set bookmarks, maybe annotate them, jump to them later
 
-;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+;; Copyright (C) 1993-1997, 2001-2012 Free Software Foundation, Inc.
 
 ;; Author: Karl Fogel <kfogel@red-bean.com>
 ;; Maintainer: Karl Fogel <kfogel@red-bean.com>
 ;; can navigate your way to that location by providing the string.
 ;; See the "User Variables" section for customizations.
 
-;; Thanks to David Bremner <bremner@cs.sfu.ca> for thinking of and
-;; then implementing the bookmark-current-bookmark idea.  He even
-;; sent *patches*, bless his soul...
-
-;; Thanks to Gregory M. Saunders <saunders@cis.ohio-state.edu> for
-;; fixing and improving bookmark-time-to-save-p.
-
-;; Thanks go to Andrew V. Klein <avk@cig.mot.com> for the code that
-;; sorts the alist before presenting it to the user (in bookmark-bmenu-list
-;; and the menu-bar).
-
-;; And much thanks to David Hughes <djh@harston.cv.com> for many small
-;; suggestions and the code to implement them (like
-;; bookmark-bmenu-check-position, and some of the Lucid compatibility
-;; stuff).
-
-;; Kudos (whatever they are) go to Jim Blandy <jimb@red-bean.com>
-;; for his eminently sensible suggestion to separate bookmark-jump
-;; into bookmark-jump and bookmark-jump-noselect, which made many
-;; other things cleaner as well.
-
-;; Thanks to Roland McGrath for encouragement and help with defining
-;; autoloads on the menu-bar.
-
-;; Jonathan Stigelman <stig@hackvan.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!)
-
-;; Buckets of gratitude to John Grabowski <johng@media.mit.edu> for
-;; thinking up the annotations feature and implementing it so well.
-
-;; Based on info-bookmark.el, by Karl Fogel and Ken Olstad
-;; <olstad@msc.edu>.
-
-;; Thanks to Mikio Nakajima <PBC01764@niftyserve.or.jp> for many bugs
-;; reported and fixed.
-
-;; Thank you, Michael Kifer, for contributing the XEmacs support.
-
-;; Enough with the credits already, get on to the good stuff:
-
-;; 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?
 \f
 ;;; Code:
 
 (require 'pp)
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
 
 ;;; Misc comments:
 ;;
 (defcustom bookmark-save-flag t
   "Controls when Emacs saves bookmarks to a file.
 --> nil means never save bookmarks, except when `bookmark-save' is
-    explicitly called \(\\[bookmark-save]\).
+    explicitly called (\\[bookmark-save]).
 --> t means save bookmarks when Emacs is killed.
 --> Otherwise, 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
+    the bookmark list is saved (i.e.: the number of times which
+    Emacs's 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.
 
 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.\)
+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
 `bookmark-default-file', which is `~/.emacs.bmk' by default."
@@ -129,7 +83,7 @@ To specify the file in which to save them, modify the variable
   "The `.emacs.bmk' file used to be called this name.")
 
 
-;; defvarred to avoid a compilation warning:
+;; defvared to avoid a compilation warning:
 (defvar bookmark-file nil
   "Old name for `bookmark-default-file'.")
 
@@ -137,7 +91,7 @@ To specify the file in which to save them, modify the variable
   (if bookmark-file
       ;; In case user set `bookmark-file' in her .emacs:
       bookmark-file
-    (convert-standard-filename "~/.emacs.bmk"))
+    (locate-user-emacs-file "bookmarks" ".emacs.bmk"))
   "File in which to save bookmarks by default."
   :type 'file
   :group 'bookmark)
@@ -174,6 +128,13 @@ recently set ones come first, oldest ones come last)."
   :group 'bookmark)
 
 
+(defconst bookmark-bmenu-header-height 2
+  "Number of lines used for the *Bookmark List* header.")
+
+(defconst bookmark-bmenu-marks-width 2
+  "Number of columns (chars) used for the *Bookmark List* marks column,
+including the annotations column.")
+
 (defcustom bookmark-bmenu-file-column 30
   "Column at which to display filenames in a buffer listing bookmarks.
 You can toggle whether files are shown with \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-toggle-filenames]."
@@ -186,7 +147,7 @@ You can toggle whether files are shown with \\<bookmark-bmenu-mode-map>\\[bookma
 This may result in truncated bookmark names.  To disable this, put the
 following in your `.emacs' file:
 
-\(setq bookmark-bmenu-toggle-filenames nil\)"
+\(setq bookmark-bmenu-toggle-filenames nil)"
   :type 'boolean
   :group 'bookmark)
 
@@ -292,7 +253,7 @@ or the deprecated form (BOOKMARK-NAME PARAM-ALIST).
  for instance.  HANDLER must accept a bookmark as argument.")
 
 (defvar bookmarks-already-loaded nil
-  "Non-nil iff bookmarks have been loaded from `bookmark-default-file'.")
+  "Non-nil if and only if bookmarks have been loaded from `bookmark-default-file'.")
 
 
 ;; more stuff added by db.
@@ -316,28 +277,36 @@ through a file easier.")
 (defvar bookmark-current-buffer nil
   "The buffer in which a bookmark is currently being set or renamed.
 Functions that insert strings into the minibuffer use this to know
-the source buffer for that information; see `bookmark-yank-word' and
-`bookmark-insert-current-bookmark' for example.")
+the source buffer for that information; see `bookmark-yank-word'
+for example.")
 
 
 (defvar bookmark-yank-point 0
   "The next point from which to pull source text for `bookmark-yank-word'.
-This point is in `bookmark-curent-buffer'.")
+This point is in `bookmark-current-buffer'.")
 
 
 (defvar bookmark-quit-flag nil
   "Non nil make `bookmark-bmenu-search' quit immediately.")
 \f
-;; Helper functions.
-
-;; Only functions on this page and the next one (file formats) need to
-;; know anything about the format of bookmark-alist entries.
+;; Helper functions and macros.
+
+(defmacro with-buffer-modified-unmodified (&rest body)
+  "Run BODY while preserving the buffer's `buffer-modified-p' state."
+  (let ((was-modified (make-symbol "was-modified")))
+    `(let ((,was-modified (buffer-modified-p)))
+       (unwind-protect
+           (progn ,@body)
+         (set-buffer-modified-p ,was-modified)))))
+
+;; Only functions below, in this page and the next one (file formats),
+;; need to know anything about the format of bookmark-alist entries.
 ;; Everyone else should go through them.
 
-
-(defun bookmark-name-from-full-record (full-record)
-  "Return name of FULL-RECORD \(an alist element instead of a string\)."
-  (car full-record))
+(defun bookmark-name-from-full-record (bookmark-record)
+  "Return the name of BOOKMARK-RECORD.  BOOKMARK-RECORD is, e.g.,
+one element from `bookmark-alist'."
+  (car bookmark-record))
 
 
 (defun bookmark-all-names ()
@@ -346,113 +315,100 @@ This point is in `bookmark-curent-buffer'.")
   (mapcar 'bookmark-name-from-full-record bookmark-alist))
 
 
-(defun bookmark-get-bookmark (bookmark &optional noerror)
-  "Return the bookmark record corresponding to BOOKMARK.
-If BOOKMARK is a string, look for the corresponding bookmark record in
-`bookmark-alist'; return it if found, otherwise error.  Else if
-BOOKMARK is already a bookmark record, just return it."
+(defun bookmark-get-bookmark (bookmark-name-or-record &optional noerror)
+  "Return the bookmark record corresponding to BOOKMARK-NAME-OR-RECORD.
+If BOOKMARK-NAME-OR-RECORD is a string, look for the corresponding
+bookmark record in `bookmark-alist'; return it if found, otherwise
+error.  Else if BOOKMARK-NAME-OR-RECORD is already a bookmark record,
+just return it."
   (cond
-   ((consp bookmark) bookmark)
-   ((stringp bookmark)
-    (or (assoc-string bookmark bookmark-alist bookmark-completion-ignore-case)
-        (unless noerror (error "Invalid bookmark %s" bookmark))))))
-
-
-(defun bookmark-get-bookmark-record (bookmark)
-  "Return the record portion of the entry for BOOKMARK in
-`bookmark-alist' (that is, all information but the name).
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (let ((alist (cdr (bookmark-get-bookmark bookmark))))
+   ((consp bookmark-name-or-record) bookmark-name-or-record)
+   ((stringp bookmark-name-or-record)
+    (or (assoc-string bookmark-name-or-record bookmark-alist
+                      bookmark-completion-ignore-case)
+        (unless noerror (error "Invalid bookmark %s"
+                               bookmark-name-or-record))))))
+
+
+(defun bookmark-get-bookmark-record (bookmark-name-or-record)
+  "Return the record portion of the entry for BOOKMARK-NAME-OR-RECORD in
+`bookmark-alist' (that is, all information but the name)."
+  (let ((alist (cdr (bookmark-get-bookmark bookmark-name-or-record))))
     ;; The bookmark objects can either look like (NAME ALIST) or
     ;; (NAME . ALIST), so we have to distinguish the two here.
     (if (and (null (cdr alist)) (consp (caar alist)))
         (car alist) alist)))
 
 
-(defun bookmark-set-name (bookmark newname)
-  "Set BOOKMARK's name to NEWNAME.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (setcar
-   (if (stringp bookmark) (bookmark-get-bookmark bookmark) bookmark)
-   newname))
+(defun bookmark-set-name (bookmark-name-or-record newname)
+  "Set BOOKMARK-NAME-OR-RECORD's name to NEWNAME."
+  (setcar (bookmark-get-bookmark bookmark-name-or-record) newname))
 
-(defun bookmark-prop-get (bookmark prop)
-  "Return the property PROP of BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (cdr (assq prop (bookmark-get-bookmark-record bookmark))))
+(defun bookmark-prop-get (bookmark-name-or-record prop)
+  "Return the property PROP of BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (cdr (assq prop (bookmark-get-bookmark-record bookmark-name-or-record))))
 
-(defun bookmark-prop-set (bookmark prop val)
-  "Set the property PROP of BOOKMARK to VAL.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (let ((cell (assq prop (bookmark-get-bookmark-record bookmark))))
+(defun bookmark-prop-set (bookmark-name-or-record prop val)
+  "Set the property PROP of BOOKMARK-NAME-OR-RECORD to VAL."
+  (let ((cell (assq
+               prop (bookmark-get-bookmark-record bookmark-name-or-record))))
     (if cell
         (setcdr cell val)
-      (nconc (bookmark-get-bookmark-record bookmark)
+      (nconc (bookmark-get-bookmark-record bookmark-name-or-record)
              (list (cons prop val))))))
 
-(defun bookmark-get-annotation (bookmark)
-  "Return the annotation of BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-get bookmark 'annotation))
+(defun bookmark-get-annotation (bookmark-name-or-record)
+  "Return the annotation of BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (bookmark-prop-get bookmark-name-or-record 'annotation))
 
-(defun bookmark-set-annotation (bookmark ann)
-  "Set the annotation of BOOKMARK to ANN.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-set bookmark 'annotation ann))
+(defun bookmark-set-annotation (bookmark-name-or-record ann)
+  "Set the annotation of BOOKMARK-NAME-OR-RECORD to ANN."
+  (bookmark-prop-set bookmark-name-or-record 'annotation ann))
 
 
-(defun bookmark-get-filename (bookmark)
-  "Return the full filename of BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-get bookmark 'filename))
+(defun bookmark-get-filename (bookmark-name-or-record)
+  "Return the full filename of BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (bookmark-prop-get bookmark-name-or-record 'filename))
 
 
-(defun bookmark-set-filename (bookmark filename)
-  "Set the full filename of BOOKMARK to FILENAME.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-set bookmark 'filename filename))
+(defun bookmark-set-filename (bookmark-name-or-record filename)
+  "Set the full filename of BOOKMARK-NAME-OR-RECORD to FILENAME."
+  (bookmark-prop-set bookmark-name-or-record 'filename filename))
 
 
-(defun bookmark-get-position (bookmark)
-  "Return the position \(i.e.: point\) of BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-get bookmark 'position))
+(defun bookmark-get-position (bookmark-name-or-record)
+  "Return the position (i.e.: point) of BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (bookmark-prop-get bookmark-name-or-record 'position))
 
 
-(defun bookmark-set-position (bookmark position)
-  "Set the position \(i.e.: point\) of BOOKMARK to POSITION.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-set bookmark 'position position))
+(defun bookmark-set-position (bookmark-name-or-record position)
+  "Set the position (i.e.: point) of BOOKMARK-NAME-OR-RECORD to POSITION."
+  (bookmark-prop-set bookmark-name-or-record 'position position))
 
 
-(defun bookmark-get-front-context-string (bookmark)
-  "Return the front-context-string of BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-get bookmark 'front-context-string))
+(defun bookmark-get-front-context-string (bookmark-name-or-record)
+  "Return the front-context-string of BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (bookmark-prop-get bookmark-name-or-record 'front-context-string))
 
 
-(defun bookmark-set-front-context-string (bookmark string)
-  "Set the front-context-string of BOOKMARK to STRING.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-set bookmark 'front-context-string string))
+(defun bookmark-set-front-context-string (bookmark-name-or-record string)
+  "Set the front-context-string of BOOKMARK-NAME-OR-RECORD to STRING."
+  (bookmark-prop-set bookmark-name-or-record 'front-context-string string))
 
 
-(defun bookmark-get-rear-context-string (bookmark)
-  "Return the rear-context-string of BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-get bookmark 'rear-context-string))
+(defun bookmark-get-rear-context-string (bookmark-name-or-record)
+  "Return the rear-context-string of BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (bookmark-prop-get bookmark-name-or-record 'rear-context-string))
 
 
-(defun bookmark-set-rear-context-string (bookmark string)
-  "Set the rear-context-string of BOOKMARK to STRING.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-set bookmark 'rear-context-string string))
+(defun bookmark-set-rear-context-string (bookmark-name-or-record string)
+  "Set the rear-context-string of BOOKMARK-NAME-OR-RECORD to STRING."
+  (bookmark-prop-set bookmark-name-or-record 'rear-context-string string))
 
 
-(defun bookmark-get-handler (bookmark)
-  "Return the handler function for BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
-  (bookmark-prop-get bookmark 'handler))
+(defun bookmark-get-handler (bookmark-name-or-record)
+  "Return the handler function for BOOKMARK-NAME-OR-RECORD, or nil if none."
+  (bookmark-prop-get bookmark-name-or-record 'handler))
 
 (defvar bookmark-history nil
   "The history list for bookmark functions.")
@@ -517,6 +473,12 @@ equivalently just return ALIST without NAME.")
 (defun bookmark-make-record ()
   "Return a new bookmark record (NAME . ALIST) for the current location."
   (let ((record (funcall bookmark-make-record-function)))
+    ;; Set up defaults.
+    (bookmark-prop-set
+     record 'defaults
+     (delq nil (delete-dups (append (bookmark-prop-get record 'defaults)
+                                   (list bookmark-current-bookmark
+                                         (bookmark-buffer-name))))))
     ;; Set up default name.
     (if (stringp (car record))
         ;; The function already provided a default name.
@@ -559,26 +521,36 @@ old one."
     (setq bookmark-current-bookmark stripped-name)
     (bookmark-bmenu-surreptitiously-rebuild-list)))
 
-(defun bookmark-make-record-default (&optional point-only)
+(defun bookmark-make-record-default (&optional no-file no-context posn)
   "Return the record describing the location of a new bookmark.
-Must be at the correct position in the buffer in which the bookmark is
-being set.
-If POINT-ONLY is non-nil, then only return the subset of the
-record that pertains to the location within the buffer."
-  `(,@(unless point-only `((filename . ,(bookmark-buffer-file-name))))
-    (front-context-string
-     . ,(if (>= (- (point-max) (point)) bookmark-search-size)
-            (buffer-substring-no-properties
-             (point)
-             (+ (point) bookmark-search-size))
-          nil))
-    (rear-context-string
-     . ,(if (>= (- (point) (point-min)) bookmark-search-size)
-            (buffer-substring-no-properties
-             (point)
-             (- (point) bookmark-search-size))
-          nil))
-    (position . ,(point))))
+Point should be at the buffer in which the bookmark is being set,
+and normally should be at the position where the bookmark is desired,
+but see the optional arguments for other possibilities.
+
+If NO-FILE is non-nil, then only return the subset of the
+record that pertains to the location within the buffer, leaving off
+the part that records the filename.
+
+If NO-CONTEXT is non-nil, do not include the front- and rear-context
+strings in the record -- the position is enough.
+
+If POSN is non-nil, record POSN as the point instead of `(point)'."
+  `(,@(unless no-file `((filename . ,(bookmark-buffer-file-name))))
+    ,@(unless no-context `((front-context-string
+                           . ,(if (>= (- (point-max) (point))
+                                      bookmark-search-size)
+                                  (buffer-substring-no-properties
+                                   (point)
+                                   (+ (point) bookmark-search-size))
+                                  nil))))
+    ,@(unless no-context `((rear-context-string
+                           . ,(if (>= (- (point) (point-min))
+                                      bookmark-search-size)
+                                  (buffer-substring-no-properties
+                                   (point)
+                                   (- (point) bookmark-search-size))
+                                  nil))))
+    (position . ,(or posn (point)))))
 
 \f
 ;;; File format stuff
@@ -772,10 +744,6 @@ This expects to be called from `point-min' in a bookmark file."
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map minibuffer-local-map)
     (define-key map "\C-w" 'bookmark-yank-word)
-    ;; This C-u binding might not be very useful any more now that we
-    ;; provide access to the default via the standard M-n binding.
-    ;; Maybe we should just remove it?  --Stef-08
-    (define-key map "\C-u" 'bookmark-insert-current-bookmark)
     map))
 
 ;;;###autoload
@@ -800,37 +768,56 @@ this helps you use a single bookmark name to track progress through a
 large document.  If there is no prior bookmark for this document, then
 C-u inserts an appropriate name based on the buffer or file.
 
-Use \\[bookmark-delete] to remove bookmarks \(you give it a name and
+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.\)"
+the list of bookmarks.)"
   (interactive (list nil current-prefix-arg))
-  (let* ((record (bookmark-make-record))
-         (default (car record)))
-
-    (bookmark-maybe-load-default-file)
-
-    (setq bookmark-yank-point (point))
-    (setq bookmark-current-buffer (current-buffer))
+  (unwind-protect
+       (let* ((record (bookmark-make-record))
+              ;; `defaults' is a transient element of the
+              ;; extensible format described above in the section
+              ;; `File format stuff'.  Bookmark record functions
+              ;; can use it to specify a list of default values
+              ;; accessible via M-n while reading a bookmark name.
+              (defaults (bookmark-prop-get record 'defaults))
+              (default (if (consp defaults) (car defaults) defaults)))
+
+         (if defaults
+             ;; Don't store default values in the record.
+             (setq record (assq-delete-all 'defaults record))
+           ;; When no defaults in the record, use its first element.
+           (setq defaults (car record) default defaults))
+
+         (bookmark-maybe-load-default-file)
+         ;; Don't set `bookmark-yank-point' and `bookmark-current-buffer'
+         ;; if they have been already set in another buffer. (e.g gnus-art).
+         (unless (and bookmark-yank-point
+                      bookmark-current-buffer)
+           (setq bookmark-yank-point (point))
+           (setq bookmark-current-buffer (current-buffer)))
+
+         (let ((str
+                (or name
+                    (read-from-minibuffer
+                     (format "Set bookmark (%s): " default)
+                     nil
+                     bookmark-minibuffer-read-name-map
+                     nil nil defaults))))
+           (and (string-equal str "") (setq str default))
+           (bookmark-store str (cdr record) no-overwrite)
+
+           ;; Ask for an annotation buffer for this bookmark
+           (when bookmark-use-annotations
+             (bookmark-edit-annotation str))))
+    (setq bookmark-yank-point nil)
+    (setq bookmark-current-buffer nil)))
 
-    (let ((str
-           (or name
-               (read-from-minibuffer
-                (format "Set bookmark (%s): " default)
-                nil
-                bookmark-minibuffer-read-name-map
-                nil nil default))))
-      (and (string-equal str "") (setq str default))
-      (bookmark-store str (cdr record) no-overwrite)
-
-      ;; Ask for an annotation buffer for this bookmark
-      (when bookmark-use-annotations
-        (bookmark-edit-annotation str)))))
 
 (defun bookmark-kill-line (&optional newline-too)
   "Kill from point to end of line.
 If optional arg NEWLINE-TOO is non-nil, delete the newline too.
 Does not affect the kill ring."
-  (let ((eol (save-excursion (end-of-line) (point))))
+  (let ((eol (line-end-position)))
     (delete-region (point) eol)
     (if (and newline-too (looking-at "\n"))
         (delete-char 1))))
@@ -843,11 +830,11 @@ This is used in `bookmark-edit-annotation' to record the bookmark
 whose annotation is being edited.")
 
 
-(defun bookmark-default-annotation-text (bookmark)
-  "Return default annotation text for BOOKMARK (a string, not a record).
+(defun bookmark-default-annotation-text (bookmark-name)
+  "Return default annotation text for BOOKMARK-NAME.
 The default annotation text is simply some text explaining how to use
 annotations."
-  (concat "#  Type the annotation for bookmark '" bookmark "' here.\n"
+  (concat "#  Type the annotation for bookmark '" bookmark-name "' here.\n"
          "#  All lines which start with a '#' will be deleted.\n"
          "#  Type C-c C-c when done.\n#\n"
          "#  Author: " (user-full-name) " <" (user-login-name) "@"
@@ -855,11 +842,11 @@ annotations."
          "#  Date:    " (current-time-string) "\n"))
 
 
+(define-obsolete-variable-alias 'bookmark-read-annotation-text-func
+  'bookmark-edit-annotation-text-func "23.1")
 (defvar bookmark-edit-annotation-text-func 'bookmark-default-annotation-text
   "Function to return default text to use for a bookmark annotation.
 It takes one argument, the name of the bookmark, as a string.")
-(define-obsolete-variable-alias 'bookmark-read-annotation-text-func
-  'bookmark-edit-annotation-text-func "23.1")
 
 (defvar bookmark-edit-annotation-mode-map
   (let ((map (make-sparse-keymap)))
@@ -869,22 +856,20 @@ It takes one argument, the name of the bookmark, as a string.")
   "Keymap for editing an annotation of a bookmark.")
 
 
-(defun bookmark-edit-annotation-mode (bookmark)
-  "Mode for editing the annotation of bookmark BOOKMARK.
+(defun bookmark-edit-annotation-mode (bookmark-name-or-record)
+  "Mode for editing the annotation of bookmark BOOKMARK-NAME-OR-RECORD.
 When you have finished composing, type \\[bookmark-send-annotation].
 
-BOOKMARK is a bookmark name (a string) or a bookmark record.
-
 \\{bookmark-edit-annotation-mode-map}"
   (interactive)
   (kill-all-local-variables)
   (make-local-variable 'bookmark-annotation-name)
-  (setq bookmark-annotation-name bookmark)
+  (setq bookmark-annotation-name bookmark-name-or-record)
   (use-local-map bookmark-edit-annotation-mode-map)
   (setq major-mode 'bookmark-edit-annotation-mode
         mode-name "Edit Bookmark Annotation")
-  (insert (funcall bookmark-edit-annotation-text-func bookmark))
-  (let ((annotation (bookmark-get-annotation bookmark)))
+  (insert (funcall bookmark-edit-annotation-text-func bookmark-name-or-record))
+  (let ((annotation (bookmark-get-annotation bookmark-name-or-record)))
     (if (and annotation (not (string-equal annotation "")))
        (insert annotation)))
   (run-mode-hooks 'text-mode-hook))
@@ -903,29 +888,18 @@ Lines beginning with `#' are ignored."
       (forward-line 1)))
   ;; Take no chances with text properties.
   (let ((annotation (buffer-substring-no-properties (point-min) (point-max)))
-       (bookmark bookmark-annotation-name))
-    (bookmark-set-annotation bookmark annotation)
+       (bookmark-name bookmark-annotation-name))
+    (bookmark-set-annotation bookmark-name annotation)
+    (setq bookmark-alist-modification-count
+          (1+ bookmark-alist-modification-count))
     (bookmark-bmenu-surreptitiously-rebuild-list))
   (kill-buffer (current-buffer)))
 
 
-(defun bookmark-edit-annotation (bookmark)
-  "Pop up a buffer for editing bookmark BOOKMARK's annotation.
-BOOKMARK is a bookmark name (a string) or a bookmark record."
+(defun bookmark-edit-annotation (bookmark-name-or-record)
+  "Pop up a buffer for editing bookmark BOOKMARK-NAME-OR-RECORD's annotation."
   (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*"))
-  (bookmark-edit-annotation-mode bookmark))
-
-
-(defun bookmark-insert-current-bookmark ()
-  "Insert into the bookmark name currently being set the value of
-`bookmark-current-bookmark' in `bookmark-current-buffer', defaulting
-to the buffer's file name if `bookmark-current-bookmark' is nil."
-  (interactive)
-  (let ((str
-        (with-current-buffer bookmark-current-buffer
-          (or bookmark-current-bookmark
-               (bookmark-buffer-name)))))
-    (insert str)))
+  (bookmark-edit-annotation-mode bookmark-name-or-record))
 
 
 (defun bookmark-buffer-name ()
@@ -953,7 +927,7 @@ If the buffer is associated with a file or directory, use that name."
 (defun bookmark-yank-word ()
   "Get the next word from buffer `bookmark-current-buffer' and append
 it to the name of the bookmark currently being set, advancing
-`bookmark-yank-point' by one word." 
+`bookmark-yank-point' by one word."
   (interactive)
   (let ((string (with-current-buffer bookmark-current-buffer
                   (goto-char bookmark-yank-point)
@@ -987,14 +961,14 @@ it to the name of the bookmark currently being set, advancing
            (and
             ;; Possibly the old bookmark file, "~/.emacs-bkmrks", needs
             ;; to be renamed.
-            (file-exists-p (expand-file-name bookmark-old-default-file))
-            (not (file-exists-p (expand-file-name bookmark-default-file)))
-            (rename-file (expand-file-name bookmark-old-default-file)
-                         (expand-file-name bookmark-default-file)))
+            (file-exists-p bookmark-old-default-file)
+            (not (file-exists-p bookmark-default-file))
+            (rename-file bookmark-old-default-file
+                         bookmark-default-file))
            ;; return t so the `and' will continue...
            t)
 
-       (file-readable-p (expand-file-name bookmark-default-file))
+       (file-readable-p bookmark-default-file)
        (bookmark-load bookmark-default-file t t)
        (setq bookmarks-already-loaded t)))
 
@@ -1013,14 +987,14 @@ If `bookmark-sort-flag' is non-nil, then return a sorted copy of the alist."
   "Hook run after `bookmark-jump' jumps to a bookmark.
 Useful for example to unhide text in `outline-mode'.")
 
-(defun bookmark--jump-via (bookmark display-function)
-  "Handle BOOKMARK, then call DISPLAY-FUNCTION with current buffer as argument.
-Bookmark may be a bookmark name (a string) or a bookmark record.
+(defun bookmark--jump-via (bookmark-name-or-record display-function)
+  "Handle BOOKMARK-NAME-OR-RECORD, then call DISPLAY-FUNCTION with
+current buffer as argument.
 
 After calling DISPLAY-FUNCTION, set window point to the point specified
-by BOOKMARK, if necessary, run `bookmark-after-jump-hook', and then show
-any annotations for this bookmark."
-  (bookmark-handle-bookmark bookmark)
+by BOOKMARK-NAME-OR-RECORD, if necessary, run `bookmark-after-jump-hook',
+and then show any annotations for this bookmark."
+  (bookmark-handle-bookmark bookmark-name-or-record)
   (save-current-buffer
     (funcall display-function (current-buffer)))
   (let ((win (get-buffer-window (current-buffer) 0)))
@@ -1031,7 +1005,7 @@ any annotations for this bookmark."
   (if bookmark-automatically-show-annotations
       ;; if there is an annotation for this bookmark,
       ;; show it in a buffer.
-      (bookmark-show-annotation bookmark)))
+      (bookmark-show-annotation bookmark-name-or-record)))
 
 
 ;;;###autoload
@@ -1047,8 +1021,8 @@ 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.
 
-BOOKMARK may be a bookmark name (a string) or a bookmark record, but
-the latter is usually only used by programmatic callers.
+BOOKMARK is usually a bookmark name (a string).  It can also be a
+bookmark record, but this is usually only done by programmatic callers.
 
 If DISPLAY-FUNC is non-nil, it is a function to invoke to display the
 bookmark.  It defaults to `switch-to-buffer'.  A typical value for
@@ -1072,11 +1046,9 @@ DISPLAY-FUNC would be `switch-to-buffer-other-window'."
 
 
 (defun bookmark-jump-noselect (bookmark)
-  "Return the location pointed to by the bookmark BOOKMARK.
+  "Return the location pointed to by BOOKMARK (see `bookmark-jump').
 The return value has the form (BUFFER . POINT).
 
-BOOKMARK may be a bookmark name (a string) or a bookmark record.
-
 Note: this function is deprecated and is present for Emacs 22
 compatibility only."
   (save-excursion
@@ -1085,26 +1057,27 @@ compatibility only."
 
 (make-obsolete 'bookmark-jump-noselect 'bookmark-handle-bookmark "23.1")
 
-(defun bookmark-handle-bookmark (bookmark)
-  "Call BOOKMARK's handler or `bookmark-default-handler' if it has none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record.
-
-Changes current buffer and point and returns nil, or signals a `file-error'.
+(defun bookmark-handle-bookmark (bookmark-name-or-record)
+  "Call BOOKMARK-NAME-OR-RECORD's handler or `bookmark-default-handler'
+if it has none.  This changes current buffer and point and returns nil,
+or signals a `file-error'.
 
-If BOOKMARK has no file, this is a no-op.  If BOOKMARK has a file, but
-that file no longer exists, then offer interactively to relocate BOOKMARK."
+If BOOKMARK-NAME-OR-RECORD has no file, this is a no-op.  If
+BOOKMARK-NAME-OR-RECORD has a file, but that file no longer exists,
+then offer interactively to relocate BOOKMARK-NAME-OR-RECORD."
   (condition-case err
-      (funcall (or (bookmark-get-handler bookmark)
+      (funcall (or (bookmark-get-handler bookmark-name-or-record)
                    'bookmark-default-handler)
-               (bookmark-get-bookmark bookmark))
-    (file-error
+               (bookmark-get-bookmark bookmark-name-or-record))
+    (bookmark-error-no-filename         ;file-error
      ;; We were unable to find the marked file, so ask if user wants to
      ;; relocate the bookmark, else remind them to consider deletion.
-     (when (stringp bookmark)
-       ;; `bookmark' can be either a bookmark name (from `bookmark-alist')
-       ;; or a bookmark object.  If it's an object, we assume it's a
-       ;; bookmark used internally by some other package.
-       (let ((file (bookmark-get-filename bookmark)))
+     (when (stringp bookmark-name-or-record)
+       ;; `bookmark-name-or-record' can be either a bookmark name
+       ;; (from `bookmark-alist')  or a bookmark object.  If it's an
+       ;; object, we assume it's a bookmark used internally by some
+       ;; other package.
+       (let ((file (bookmark-get-filename bookmark-name-or-record)))
          (when file        ;Don't know how to relocate if there's no `file'.
            ;; If file is not a dir, directory-file-name just returns file.
            (let ((display-name (directory-file-name file)))
@@ -1117,20 +1090,20 @@ that file no longer exists, then offer interactively to relocate BOOKMARK."
              (let ((use-dialog-box nil)
                    (use-file-dialog nil))
                (if (y-or-n-p (concat display-name " nonexistent.  Relocate \""
-                                     bookmark "\"? "))
+                                     bookmark-name-or-record "\"? "))
                    (progn
-                     (bookmark-relocate bookmark)
+                     (bookmark-relocate bookmark-name-or-record)
                      ;; Try again.
-                     (funcall (or (bookmark-get-handler bookmark)
+                     (funcall (or (bookmark-get-handler bookmark-name-or-record)
                                   'bookmark-default-handler)
-                              (bookmark-get-bookmark bookmark)))
+                              (bookmark-get-bookmark bookmark-name-or-record)))
                  (message
-                  "Bookmark not relocated; consider removing it \(%s\)."
-                  bookmark)
+                  "Bookmark not relocated; consider removing it (%s)."
+                  bookmark-name-or-record)
                  (signal (car err) (cdr err))))))))))
   ;; Added by db.
-  (when (stringp bookmark)
-    (setq bookmark-current-bookmark bookmark))
+  (when (stringp bookmark-name-or-record)
+    (setq bookmark-current-bookmark bookmark-name-or-record))
   nil)
 
 (put 'bookmark-error-no-filename
@@ -1145,43 +1118,47 @@ that file no longer exists, then offer interactively to relocate BOOKMARK."
 BMK-RECORD is a bookmark record, not a bookmark name (i.e., not a string).
 Changes current buffer and point and returns nil, or signals a `file-error'."
   (let ((file          (bookmark-get-filename bmk-record))
+       (buf           (bookmark-prop-get bmk-record 'buffer))
         (forward-str   (bookmark-get-front-context-string bmk-record))
         (behind-str    (bookmark-get-rear-context-string bmk-record))
         (place         (bookmark-get-position bmk-record)))
-    (if (not file)
-        (signal 'bookmark-error-no-filename (list 'stringp file))
-      (set-buffer (find-file-noselect file))
-      (if place (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)
-              (goto-char (match-beginning 0))))
-      (if behind-str
-          (if (search-backward behind-str (point-min) t)
-              (goto-char (match-end 0)))))
+    (set-buffer
+     (cond
+      ((and file (file-readable-p file) (not (buffer-live-p buf)))
+       (find-file-noselect file))
+      ;; No file found.  See if buffer BUF have been created.
+      ((and buf (get-buffer buf)))
+      (t ;; If not, raise error.
+       (signal 'bookmark-error-no-filename (list 'stringp file)))))
+    (if place (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.
+    (when (and forward-str (search-forward forward-str (point-max) t))
+      (goto-char (match-beginning 0)))
+    (when (and behind-str (search-backward behind-str (point-min) t))
+      (goto-char (match-end 0)))
     nil))
 
 ;;;###autoload
-(defun bookmark-relocate (bookmark)
-  "Relocate BOOKMARK to another file (reading file name with minibuffer).
-BOOKMARK is a bookmark name (a string), not a bookmark record.
+(defun bookmark-relocate (bookmark-name)
+  "Relocate BOOKMARK-NAME to another file, reading file name with minibuffer.
 
 This 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."
   (interactive (list (bookmark-completing-read "Bookmark to relocate")))
-  (bookmark-maybe-historicize-string bookmark)
+  (bookmark-maybe-historicize-string bookmark-name)
   (bookmark-maybe-load-default-file)
-  (let* ((bmrk-filename (bookmark-get-filename bookmark))
-         (newloc (expand-file-name
-                  (read-file-name
-                   (format "Relocate %s to: " bookmark)
-                   (file-name-directory bmrk-filename)))))
-    (bookmark-set-filename bookmark newloc)
+  (let* ((bmrk-filename (bookmark-get-filename bookmark-name))
+         (newloc (abbreviate-file-name
+                  (expand-file-name
+                   (read-file-name
+                    (format "Relocate %s to: " bookmark-name)
+                    (file-name-directory bmrk-filename))))))
+    (bookmark-set-filename bookmark-name newloc)
     (setq bookmark-alist-modification-count
           (1+ bookmark-alist-modification-count))
     (if (bookmark-time-to-save-p)
@@ -1190,17 +1167,16 @@ after a bookmark was set in it."
 
 
 ;;;###autoload
-(defun bookmark-insert-location (bookmark &optional no-history)
-  "Insert the name of the file associated with BOOKMARK.
-BOOKMARK is a bookmark name (a string), not a bookmark record.
+(defun bookmark-insert-location (bookmark-name &optional no-history)
+  "Insert the name of the file associated with BOOKMARK-NAME.
 
 Optional second arg NO-HISTORY means don't record this in the
 minibuffer history list `bookmark-history'."
   (interactive (list (bookmark-completing-read "Insert bookmark location")))
-  (or no-history (bookmark-maybe-historicize-string bookmark))
+  (or no-history (bookmark-maybe-historicize-string bookmark-name))
   (let ((start (point)))
     (prog1
-       (insert (bookmark-location bookmark)) ; *Return this line*
+       (insert (bookmark-location bookmark-name))
       (if (display-mouse-p)
          (add-text-properties
           start
@@ -1214,46 +1190,49 @@ minibuffer history list `bookmark-history'."
 ;;;###autoload
 (defalias 'bookmark-locate 'bookmark-insert-location)
 
-(defun bookmark-location (bookmark)
-  "Return the name of the file associated with BOOKMARK, or nil if none.
-BOOKMARK may be a bookmark name (a string) or a bookmark record."
+(defun bookmark-location (bookmark-name-or-record)
+  "Return a description of the location of BOOKMARK-NAME-OR-RECORD."
   (bookmark-maybe-load-default-file)
-  (bookmark-get-filename bookmark))
+  ;; We could call the `handler' and ask for it to construct a description
+  ;; dynamically: it would open up several new possibilities, but it
+  ;; would have the major disadvantage of forcing to load each and
+  ;; every handler when the user calls bookmark-menu.
+  (or (bookmark-prop-get bookmark-name-or-record 'location)
+      (bookmark-get-filename bookmark-name-or-record)
+      "-- Unknown location --"))
 
 
 ;;;###autoload
-(defun bookmark-rename (old &optional new)
-  "Change the name of OLD bookmark to NEW name.
-If called from keyboard, prompt for OLD and NEW.  If called from
-menubar, select OLD from a menu and prompt for NEW.
-
-Both OLD and NEW are bookmark names (strings), never bookmark records.
+(defun bookmark-rename (old-name &optional new-name)
+  "Change the name of OLD-NAME bookmark to NEW-NAME name.
+If called from keyboard, prompt for OLD-NAME and NEW-NAME.
+If called from menubar, select OLD-NAME from a menu and prompt for NEW-NAME.
 
-If called from Lisp, prompt for NEW if only OLD was passed as an
-argument.  If called with two strings, then no prompting is done.  You
-must pass at least OLD when calling from Lisp.
+If called from Lisp, prompt for NEW-NAME if only OLD-NAME was passed
+as an argument.  If called with two strings, then no prompting is done.
+You must pass at least OLD-NAME when calling from Lisp.
 
 While you are entering the new name, consecutive C-w's insert
 consecutive words from the text of the buffer into the new bookmark
 name."
   (interactive (list (bookmark-completing-read "Old bookmark name")))
-  (bookmark-maybe-historicize-string old)
+  (bookmark-maybe-historicize-string old-name)
   (bookmark-maybe-load-default-file)
 
   (setq bookmark-yank-point (point))
   (setq bookmark-current-buffer (current-buffer))
-  (let ((newname
-         (or new   ; use second arg, if non-nil
+  (let ((final-new-name
+         (or new-name   ; use second arg, if non-nil
              (read-from-minibuffer
               "New name: "
               nil
               (let ((now-map (copy-keymap minibuffer-local-map)))
-                (define-key now-map  "\C-w" 'bookmark-yank-word)
+                (define-key now-map "\C-w" 'bookmark-yank-word)
                 now-map)
               nil
               'bookmark-history))))
-    (bookmark-set-name old newname)
-    (setq bookmark-current-bookmark newname)
+    (bookmark-set-name old-name final-new-name)
+    (setq bookmark-current-bookmark final-new-name)
     (bookmark-bmenu-surreptitiously-rebuild-list)
     (setq bookmark-alist-modification-count
           (1+ bookmark-alist-modification-count))
@@ -1262,21 +1241,21 @@ name."
 
 
 ;;;###autoload
-(defun bookmark-insert (bookmark)
-  "Insert the text of the file pointed to by bookmark BOOKMARK.
-BOOKMARK is a bookmark name (a string), not a bookmark record.
+(defun bookmark-insert (bookmark-name)
+  "Insert the text of the file pointed to by bookmark BOOKMARK-NAME.
+BOOKMARK-NAME is a bookmark name (a string), not a bookmark record.
 
 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."
   (interactive (list (bookmark-completing-read "Insert bookmark contents")))
-  (bookmark-maybe-historicize-string bookmark)
+  (bookmark-maybe-historicize-string bookmark-name)
   (bookmark-maybe-load-default-file)
   (let ((orig-point (point))
        (str-to-insert
         (save-current-buffer
-           (bookmark-handle-bookmark bookmark)
+           (bookmark-handle-bookmark bookmark-name)
           (buffer-string))))
     (insert str-to-insert)
     (push-mark)
@@ -1284,22 +1263,21 @@ this."
 
 
 ;;;###autoload
-(defun bookmark-delete (bookmark &optional batch)
-  "Delete BOOKMARK from the bookmark list.
-BOOKMARK is a bookmark name (a string), not a bookmark record.
+(defun bookmark-delete (bookmark-name &optional batch)
+  "Delete BOOKMARK-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\).
+not be deleted.  Defaults to the \"current\" bookmark (that is, the
+one most recently used in this file, if any).
 Optional second arg BATCH means don't update the bookmark list buffer,
 probably because we were called from there."
   (interactive
    (list (bookmark-completing-read "Delete bookmark"
                                   bookmark-current-bookmark)))
-  (bookmark-maybe-historicize-string bookmark)
+  (bookmark-maybe-historicize-string bookmark-name)
   (bookmark-maybe-load-default-file)
-  (let ((will-go (bookmark-get-bookmark bookmark 'noerror)))
+  (let ((will-go (bookmark-get-bookmark bookmark-name 'noerror)))
     (setq bookmark-alist (delq will-go bookmark-alist))
     ;; Added by db, nil bookmark-current-bookmark if the last
     ;; occurrence has been deleted
@@ -1342,7 +1320,7 @@ Don't use this in Lisp programs; use `bookmark-save' instead."
   "Save currently defined bookmarks.
 Saves by default in the file defined by the variable
 `bookmark-default-file'.  With a prefix arg, save it in file FILE
-\(second argument\).
+\(second argument).
 
 If you are calling this from Lisp, the two arguments are PARG and
 FILE, and if you just want it to write to the default file, then
@@ -1351,7 +1329,7 @@ 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.
 
 When you want to load in the bookmarks from a file, use
-\`bookmark-load\', \\[bookmark-load].  That function will prompt you
+`bookmark-load', \\[bookmark-load].  That function will prompt you
 for a file, defaulting to the file defined by variable
 `bookmark-default-file'."
   (interactive "P")
@@ -1389,7 +1367,7 @@ for a file, defaulting to the file defined by variable
       ;; Rather than a single call to `pp' we make one per bookmark.
       ;; Apparently `pp' has a poor algorithmic complexity, so this
       ;; scales a lot better.  bug#4485.
-      (dolist (i  bookmark-alist) (pp i (current-buffer)))
+      (dolist (i bookmark-alist) (pp i (current-buffer)))
       (insert ")")
       (let ((version-control
              (cond
@@ -1457,7 +1435,7 @@ method buffers use to resolve name collisions."
           ;;but there's no better default, and
           ;;I guess it's better than none at all.
           "~/" bookmark-default-file 'confirm)))
-  (setq file (expand-file-name file))
+  (setq file (abbreviate-file-name (expand-file-name file)))
   (if (not (file-readable-p file))
       (error "Cannot read bookmark file %s" file)
     (if (null no-msg)
@@ -1478,7 +1456,8 @@ method buffers use to resolve name collisions."
                 (setq bookmark-alist-modification-count
                       (1+ bookmark-alist-modification-count)))
               (if (string-equal
-                   (expand-file-name bookmark-default-file)
+                   (abbreviate-file-name
+                    (expand-file-name bookmark-default-file))
                    file)
                   (setq bookmarks-already-loaded t))
               (bookmark-bmenu-surreptitiously-rebuild-list))
@@ -1493,16 +1472,12 @@ method buffers use to resolve name collisions."
 ;; Prefix is "bookmark-bmenu" for "buffer-menu":
 
 
-(defvar bookmark-bmenu-bookmark-column nil)
-
-
 (defvar bookmark-bmenu-hidden-bookmarks ())
 
 
 (defvar bookmark-bmenu-mode-map
   (let ((map (make-keymap)))
-    (suppress-keymap map t)
-    (define-key map "q" 'quit-window)
+    (set-keymap-parent map special-mode-map)
     (define-key map "v" 'bookmark-bmenu-select)
     (define-key map "w" 'bookmark-bmenu-locate)
     (define-key map "2" 'bookmark-bmenu-2-window)
@@ -1522,7 +1497,6 @@ method buffers use to resolve name collisions."
     (define-key map "n" 'next-line)
     (define-key map "p" 'previous-line)
     (define-key map "\177" 'bookmark-bmenu-backup-unmark)
-    (define-key map "?" 'describe-mode)
     (define-key map "u" 'bookmark-bmenu-unmark)
     (define-key map "m" 'bookmark-bmenu-mark)
     (define-key map "l" 'bookmark-bmenu-load)
@@ -1532,9 +1506,7 @@ method buffers use to resolve name collisions."
     (define-key map "a" 'bookmark-bmenu-show-annotation)
     (define-key map "A" 'bookmark-bmenu-show-all-annotations)
     (define-key map "e" 'bookmark-bmenu-edit-annotation)
-    ;; The original binding of M-g hides the M-g prefix map.
-    ;; If someone has a better idea than M-g s, I'm open to suggestions.
-    (define-key map [?\M-g ?s] 'bookmark-bmenu-search)
+    (define-key map "/" 'bookmark-bmenu-search)
     (define-key map [mouse-2] 'bookmark-bmenu-other-window-with-mouse)
     map))
 
@@ -1569,9 +1541,7 @@ deletion, or > if it is flagged for displaying."
   (bookmark-maybe-load-default-file)
   (let ((buf (get-buffer-create "*Bookmark List*")))
     (if (called-interactively-p 'interactive)
-        (if (or (window-dedicated-p) (window-minibuffer-p))
-            (pop-to-buffer buf)
-          (switch-to-buffer buf))
+        (switch-to-buffer buf)
       (set-buffer buf)))
   (let ((inhibit-read-only t))
     (erase-buffer)
@@ -1579,29 +1549,31 @@ deletion, or > if it is flagged for displaying."
     (add-text-properties (point-min) (point)
                         '(font-lock-face bookmark-menu-heading))
     (dolist (full-record (bookmark-maybe-sort-alist))
-      ;; if a bookmark has an annotation, prepend a "*"
-      ;; in the list of bookmarks.
-      (let ((annotation (bookmark-get-annotation full-record)))
+      (let ((name        (bookmark-name-from-full-record full-record))
+            (annotation  (bookmark-get-annotation full-record))
+            (start       (point))
+            end)
+        ;; if a bookmark has an annotation, prepend a "*"
+        ;; in the list of bookmarks.
         (insert (if (and annotation (not (string-equal annotation "")))
-                    " *" "  "))
-        (let ((start (point)))
-          (insert (bookmark-name-from-full-record full-record))
-          (if (display-mouse-p)
-              (add-text-properties
-               start
-               (save-excursion (re-search-backward
-                                "[^ \t]")
-                               (1+ (point)))
-               '(mouse-face highlight
-                 follow-link t
-                 help-echo "mouse-2: go to this bookmark in other window")))
-          (insert "\n")))))
-
-  (goto-char (point-min))
-  (forward-line 2)
-  (bookmark-bmenu-mode)
-  (if bookmark-bmenu-toggle-filenames
-      (bookmark-bmenu-toggle-filenames t)))
+                    " *" "  ")
+                name)
+        (setq end (point))
+        (put-text-property
+         (+ bookmark-bmenu-marks-width start) end 'bookmark-name-prop name)
+        (when (display-mouse-p)
+          (add-text-properties
+           (+ bookmark-bmenu-marks-width start) end
+           '(mouse-face highlight
+             follow-link t
+             help-echo "mouse-2: go to this bookmark in other window")))
+        (insert "\n")))
+    (set-buffer-modified-p (not (= bookmark-alist-modification-count 0)))
+    (goto-char (point-min))
+    (forward-line 2)
+    (bookmark-bmenu-mode)
+    (if bookmark-bmenu-toggle-filenames
+        (bookmark-bmenu-toggle-filenames t))))
 
 ;;;###autoload
 (defalias 'list-bookmarks 'bookmark-bmenu-list)
@@ -1610,7 +1582,7 @@ deletion, or > if it is flagged for displaying."
 
 
 
-(defun bookmark-bmenu-mode ()
+(define-derived-mode bookmark-bmenu-mode special-mode "Bookmark Menu"
   "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.
@@ -1628,8 +1600,8 @@ Bookmark names preceded by a \"*\" have annotations.
 \\[bookmark-bmenu-other-window] -- select this bookmark in another window,
   so the bookmark menu bookmark remains visible in its window.
 \\[bookmark-bmenu-switch-other-window] -- switch the other window to this bookmark.
-\\[bookmark-bmenu-rename] -- rename this bookmark \(prompts for new name\).
-\\[bookmark-bmenu-relocate] -- relocate this bookmark's file \(prompts for new file\).
+\\[bookmark-bmenu-rename] -- rename this bookmark (prompts for new name).
+\\[bookmark-bmenu-relocate] -- relocate this bookmark's file (prompts for new file).
 \\[bookmark-bmenu-delete] -- mark this bookmark to be deleted, and move down.
 \\[bookmark-bmenu-delete-backwards] -- mark this bookmark to be deleted, and move up.
 \\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[bookmark-bmenu-delete]'.
@@ -1643,13 +1615,8 @@ Bookmark names preceded by a \"*\" have annotations.
   in another buffer.
 \\[bookmark-bmenu-show-all-annotations] -- show the annotations of all bookmarks in another buffer.
 \\[bookmark-bmenu-edit-annotation] -- edit the annotation for the current bookmark."
-  (kill-all-local-variables)
-  (use-local-map bookmark-bmenu-mode-map)
   (setq truncate-lines t)
-  (setq buffer-read-only t)
-  (setq major-mode 'bookmark-bmenu-mode)
-  (setq mode-name "Bookmark Menu")
-  (run-mode-hooks 'bookmark-bmenu-mode-hook))
+  (setq buffer-read-only t))
 
 
 (defun bookmark-bmenu-toggle-filenames (&optional show)
@@ -1675,128 +1642,90 @@ Non-nil FORCE forces a redisplay showing the filenames.  FORCE is used
 mainly for debugging, and should not be necessary in normal use."
   (if (and (not force) bookmark-bmenu-toggle-filenames)
       nil ;already shown, so do nothing
-    (save-excursion
-      (save-window-excursion
-        (goto-char (point-min))
-        (forward-line 2)
-        (setq bookmark-bmenu-hidden-bookmarks ())
-        (let ((inhibit-read-only t))
-          (while (< (point) (point-max))
-            (let ((bmrk (bookmark-bmenu-bookmark)))
-              (setq bookmark-bmenu-hidden-bookmarks
-                    (cons bmrk bookmark-bmenu-hidden-bookmarks))
-             (let ((start (save-excursion (end-of-line) (point))))
-               (move-to-column bookmark-bmenu-file-column t)
-               ;; Strip off `mouse-face' from the white spaces region.
-               (if (display-mouse-p)
-                   (remove-text-properties start (point)
-                                           '(mouse-face nil help-echo nil))))
-             (delete-region (point) (progn (end-of-line) (point)))
-              (insert "  ")
-              ;; Pass the NO-HISTORY arg:
-              (bookmark-insert-location bmrk t)
-              (forward-line 1))))))))
+    (with-buffer-modified-unmodified
+     (save-excursion
+       (save-window-excursion
+         (goto-char (point-min))
+         (forward-line 2)
+         (setq bookmark-bmenu-hidden-bookmarks ())
+         (let ((inhibit-read-only t))
+           (while (< (point) (point-max))
+             (let ((bmrk (bookmark-bmenu-bookmark)))
+               (push bmrk bookmark-bmenu-hidden-bookmarks)
+               (let ((start (line-end-position)))
+                 (move-to-column bookmark-bmenu-file-column t)
+                 ;; Strip off `mouse-face' from the white spaces region.
+                 (if (display-mouse-p)
+                     (remove-text-properties start (point)
+                                             '(mouse-face nil help-echo nil))))
+               (delete-region (point) (progn (end-of-line) (point)))
+               (insert "  ")
+               ;; Pass the NO-HISTORY arg:
+               (bookmark-insert-location bmrk t)
+               (forward-line 1)))))))))
 
 
 (defun bookmark-bmenu-hide-filenames (&optional force)
   "In an interactive bookmark list, hide the filenames of the bookmarks.
 Non-nil FORCE forces a redisplay showing the filenames.  FORCE is used
 mainly for debugging, and should not be necessary in normal use."
-  (if (and (not force) bookmark-bmenu-toggle-filenames)
-      ;; nothing to hide if above is nil
-      (save-excursion
-        (save-window-excursion
-          (goto-char (point-min))
-          (forward-line 2)
-          (setq bookmark-bmenu-hidden-bookmarks
-                (nreverse bookmark-bmenu-hidden-bookmarks))
-          (save-excursion
-            (goto-char (point-min))
-            (search-forward "Bookmark")
-            (backward-word 1)
-            (setq bookmark-bmenu-bookmark-column (current-column)))
-          (save-excursion
-            (let ((inhibit-read-only t))
-              (while bookmark-bmenu-hidden-bookmarks
-                (move-to-column bookmark-bmenu-bookmark-column t)
-                (bookmark-kill-line)
-               (let ((start (point)))
-                 (insert (car bookmark-bmenu-hidden-bookmarks))
-                 (if (display-mouse-p)
-                     (add-text-properties
-                      start
-                      (save-excursion (re-search-backward
-                                       "[^ \t]")
-                                      (1+ (point)))
-                      '(mouse-face highlight
-                        follow-link t
-                        help-echo
-                        "mouse-2: go to this bookmark in other window"))))
-                (setq bookmark-bmenu-hidden-bookmarks
-                      (cdr bookmark-bmenu-hidden-bookmarks))
-                (forward-line 1))))))))
-
-
-(defun bookmark-bmenu-check-position ()
+  (when (and (not force) bookmark-bmenu-toggle-filenames)
+    ;; nothing to hide if above is nil
+    (with-buffer-modified-unmodified
+     (save-excursion
+       (goto-char (point-min))
+       (forward-line 2)
+       (setq bookmark-bmenu-hidden-bookmarks
+             (nreverse bookmark-bmenu-hidden-bookmarks))
+       (let ((inhibit-read-only t))
+         (while bookmark-bmenu-hidden-bookmarks
+           (move-to-column bookmark-bmenu-marks-width t)
+           (bookmark-kill-line)
+           (let ((name  (pop bookmark-bmenu-hidden-bookmarks))
+                 (start (point)))
+             (insert name)
+             (put-text-property start (point) 'bookmark-name-prop name)
+             (if (display-mouse-p)
+                 (add-text-properties
+                  start (point)
+                  '(mouse-face
+                    highlight follow-link t help-echo
+                    "mouse-2: go to this bookmark in other window"))))
+           (forward-line 1)))))))
+
+
+(defun bookmark-bmenu-ensure-position ()
   "If point is not on a bookmark line, move it to one.
-If before the first bookmark line, move it to the first.
-If after the last, move it to the last.
-Return `bookmark-alist'"
-  ;; FIXME: The doc string originally implied that this returns nil if
-  ;; not on a bookmark, which is false.  Is there any real reason to
-  ;; return `bookmark-alist'?  This seems to be called in a few places
-  ;; as a check of whether point is on a bookmark line.  Those
-  ;; "checks" are in fact no-ops, since this never returns nil.
-  ;; -dadams, 2009-10-10
-  (cond ((< (count-lines (point-min) (point)) 2)
+If before the first bookmark line, move to the first; if after the
+last full line, move to the last full line.  The return value is undefined."
+  (cond ((< (count-lines (point-min) (point)) bookmark-bmenu-header-height)
          (goto-char (point-min))
-         (forward-line 2)
-         bookmark-alist)
+         (forward-line bookmark-bmenu-header-height))
         ((and (bolp) (eobp))
-         (beginning-of-line 0)
-         bookmark-alist)
-        (t
-         bookmark-alist)))
+         (beginning-of-line 0))))
 
 
 (defun bookmark-bmenu-bookmark ()
   "Return the bookmark for this line in an interactive bookmark list buffer."
-  (if (bookmark-bmenu-check-position)
-      (save-excursion
-        (save-window-excursion
-          (goto-char (point-min))
-          (search-forward "Bookmark")
-          (backward-word 1)
-          (setq bookmark-bmenu-bookmark-column (current-column)))))
-  (if bookmark-bmenu-toggle-filenames
-      (bookmark-bmenu-hide-filenames))
+  (bookmark-bmenu-ensure-position)
   (save-excursion
-    (save-window-excursion
-      (beginning-of-line)
-      (forward-char bookmark-bmenu-bookmark-column)
-      (prog1
-          (buffer-substring-no-properties (point)
-                            (progn
-                              (end-of-line)
-                              (point)))
-        ;; well, this is certainly crystal-clear:
-        (if bookmark-bmenu-toggle-filenames
-            (bookmark-bmenu-toggle-filenames t))))))
-
-
-(defun bookmark-show-annotation (bookmark)
-  "Display the annotation for bookmark named BOOKMARK in a buffer,
+    (beginning-of-line)
+    (forward-char bookmark-bmenu-marks-width)
+    (get-text-property (point) 'bookmark-name-prop)))
+
+
+(defun bookmark-show-annotation (bookmark-name-or-record)
+  "Display the annotation for BOOKMARK-NAME-OR-RECORD in a buffer,
 if an annotation exists."
-  (let ((annotation (bookmark-get-annotation bookmark)))
-    (if (and annotation (not (string-equal annotation "")))
-        (save-excursion
-          (let ((old-buf (current-buffer)))
-            (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t)
-            (delete-region (point-min) (point-max))
-            ;; (insert (concat "Annotation for bookmark '" bookmark "':\n\n"))
-            (insert annotation)
-            (goto-char (point-min))
-            (pop-to-buffer old-buf))))))
+  (let ((annotation (bookmark-get-annotation bookmark-name-or-record)))
+    (when (and annotation (not (string-equal annotation "")))
+      (save-excursion
+        (let ((old-buf (current-buffer)))
+          (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t)
+          (delete-region (point-min) (point-max))
+          (insert annotation)
+          (goto-char (point-min))
+          (switch-to-buffer-other-window old-buf))))))
 
 
 (defun bookmark-show-all-annotations ()
@@ -1825,44 +1754,58 @@ if an annotation exists."
   "Mark bookmark on this line to be displayed by \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-select]."
   (interactive)
   (beginning-of-line)
-  (if (bookmark-bmenu-check-position)
-      (let ((inhibit-read-only t))
-        (delete-char 1)
-        (insert ?>)
-        (forward-line 1)
-        (bookmark-bmenu-check-position))))
+  (bookmark-bmenu-ensure-position)
+  (with-buffer-modified-unmodified
+   (let ((inhibit-read-only t))
+     (delete-char 1)
+     (insert ?>)
+     (forward-line 1)
+     (bookmark-bmenu-ensure-position))))
 
 
 (defun bookmark-bmenu-select ()
   "Select this line's bookmark; also display bookmarks marked with `>'.
 You can mark bookmarks with the \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-mark] command."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (let ((bmrk (bookmark-bmenu-bookmark))
-            (menu (current-buffer))
-            (others ())
-            tem)
-        (goto-char (point-min))
-        (while (re-search-forward "^>" nil t)
-          (setq tem (bookmark-bmenu-bookmark))
-          (let ((inhibit-read-only t))
-            (delete-char -1)
-            (insert ?\s))
-          (or (string-equal tem bmrk)
-              (member 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 others
-            (while others
-              (split-window nil tem)
-              (other-window 1)
-              (bookmark-jump (car others))
-              (setq others (cdr others)))
-          (other-window 1)))))
+  (let ((bmrk (bookmark-bmenu-bookmark))
+        (menu (current-buffer))
+        (others ())
+        tem)
+    (goto-char (point-min))
+    (while (re-search-forward "^>" nil t)
+      (setq tem (bookmark-bmenu-bookmark))
+      (let ((inhibit-read-only t))
+        (delete-char -1)
+        (insert ?\s))
+      (or (string-equal tem bmrk)
+          (member 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 others
+        (while others
+          (split-window nil tem)
+          (other-window 1)
+          (bookmark-jump (car others))
+          (setq others (cdr others)))
+      (other-window 1))))
+
+
+(defun bookmark-bmenu-any-marks ()
+  "Return non-nil if any bookmarks are marked in the marks column."
+  (save-excursion
+    (goto-char (point-min))
+    (bookmark-bmenu-ensure-position)
+    (catch 'found-mark
+      (while (not (eobp))
+        (beginning-of-line)
+        (if (looking-at "^\\S-")
+            (throw 'found-mark t)
+          (forward-line 1)))
+      nil)))
 
 
 (defun bookmark-bmenu-save (parg)
@@ -1871,57 +1814,51 @@ With a prefix arg, prompts for a file to save them in."
   (interactive "P")
   (save-excursion
     (save-window-excursion
-      (bookmark-save parg))))
+      (bookmark-save parg)
+      (set-buffer-modified-p nil))))
 
 
 (defun bookmark-bmenu-load ()
   "Load the bookmark file and rebuild the bookmark menu-buffer."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (save-excursion
-        (save-window-excursion
-          ;; This will call `bookmark-bmenu-list'
-          (call-interactively 'bookmark-load)))))
+  (bookmark-bmenu-ensure-position)
+  (save-excursion
+    (save-window-excursion
+      ;; This will call `bookmark-bmenu-list'
+      (call-interactively 'bookmark-load))))
 
 
 (defun bookmark-bmenu-1-window ()
   "Select this line's bookmark, alone, in full frame."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (progn
-        (bookmark-jump (bookmark-bmenu-bookmark))
-        (bury-buffer (other-buffer))
-        (delete-other-windows))))
+  (bookmark-jump (bookmark-bmenu-bookmark))
+  (bury-buffer (other-buffer))
+  (delete-other-windows))
 
 
 (defun bookmark-bmenu-2-window ()
   "Select this line's bookmark, with previous buffer in second window."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (let ((bmrk (bookmark-bmenu-bookmark))
-            (menu (current-buffer))
-            (pop-up-windows t))
-        (delete-other-windows)
-        (switch-to-buffer (other-buffer))
-        (let ((bookmark-automatically-show-annotations nil)) ;FIXME: needed?
-          (bookmark--jump-via bmrk 'pop-to-buffer))
-        (bury-buffer menu))))
+  (let ((bmrk (bookmark-bmenu-bookmark))
+        (menu (current-buffer))
+        (pop-up-windows t))
+    (delete-other-windows)
+    (switch-to-buffer (other-buffer) nil t)
+    (bookmark--jump-via bmrk 'pop-to-buffer)
+    (bury-buffer menu)))
 
 
 (defun bookmark-bmenu-this-window ()
   "Select this line's bookmark in this window."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (bookmark-jump (bookmark-bmenu-bookmark))))
+  (bookmark-jump (bookmark-bmenu-bookmark)))
 
 
 (defun bookmark-bmenu-other-window ()
   "Select this line's bookmark in other window, leaving bookmark menu visible."
   (interactive)
   (let ((bookmark (bookmark-bmenu-bookmark)))
-    (if (bookmark-bmenu-check-position)
-        (let ((bookmark-automatically-show-annotations t)) ;FIXME: needed?
-          (bookmark--jump-via bookmark 'switch-to-buffer-other-window)))))
+    (bookmark--jump-via bookmark 'switch-to-buffer-other-window)))
 
 
 (defun bookmark-bmenu-switch-other-window ()
@@ -1932,9 +1869,7 @@ The current window remains selected."
         (pop-up-windows t)
         same-window-buffer-names
         same-window-regexps)
-    (if (bookmark-bmenu-check-position)
-        (let ((bookmark-automatically-show-annotations t)) ;FIXME: needed?
-          (bookmark--jump-via bookmark 'display-buffer)))))
+    (bookmark--jump-via bookmark 'display-buffer)))
 
 (defun bookmark-bmenu-other-window-with-mouse (event)
   "Select bookmark at the mouse pointer in other window, leaving bookmark menu visible."
@@ -1949,8 +1884,7 @@ The current window remains selected."
   "Show the annotation for the current bookmark in another window."
   (interactive)
   (let ((bookmark (bookmark-bmenu-bookmark)))
-    (if (bookmark-bmenu-check-position)
-       (bookmark-show-annotation bookmark))))
+    (bookmark-show-annotation bookmark)))
 
 
 (defun bookmark-bmenu-show-all-annotations ()
@@ -1963,8 +1897,7 @@ The current window remains selected."
   "Edit the annotation for the current bookmark in another window."
   (interactive)
   (let ((bookmark (bookmark-bmenu-bookmark)))
-    (if (bookmark-bmenu-check-position)
-       (bookmark-edit-annotation bookmark))))
+    (bookmark-edit-annotation bookmark)))
 
 
 (defun bookmark-bmenu-unmark (&optional backup)
@@ -1972,27 +1905,26 @@ The current window remains selected."
 Optional BACKUP means move up."
   (interactive "P")
   (beginning-of-line)
-  (if (bookmark-bmenu-check-position)
-      (progn
-        (let ((inhibit-read-only t))
-          (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))
-        (bookmark-bmenu-check-position))))
+  (bookmark-bmenu-ensure-position)
+  (with-buffer-modified-unmodified
+   (let ((inhibit-read-only t))
+     (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))
+   (bookmark-bmenu-ensure-position)))
 
 
 (defun bookmark-bmenu-backup-unmark ()
   "Move up and cancel all requested operations on bookmark on line above."
   (interactive)
   (forward-line -1)
-  (if (bookmark-bmenu-check-position)
-      (progn
-        (bookmark-bmenu-unmark)
-        (forward-line -1)
-        (bookmark-bmenu-check-position))))
+  (bookmark-bmenu-ensure-position)
+  (bookmark-bmenu-unmark)
+  (forward-line -1)
+  (bookmark-bmenu-ensure-position))
 
 
 (defun bookmark-bmenu-delete ()
@@ -2000,12 +1932,13 @@ Optional BACKUP means move up."
 To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\[bookmark-bmenu-execute-deletions]."
   (interactive)
   (beginning-of-line)
-  (if (bookmark-bmenu-check-position)
-      (let ((inhibit-read-only t))
-        (delete-char 1)
-        (insert ?D)
-        (forward-line 1)
-        (bookmark-bmenu-check-position))))
+  (bookmark-bmenu-ensure-position)
+  (with-buffer-modified-unmodified
+   (let ((inhibit-read-only t))
+     (delete-char 1)
+     (insert ?D)
+     (forward-line 1)
+     (bookmark-bmenu-ensure-position))))
 
 
 (defun bookmark-bmenu-delete-backwards ()
@@ -2014,35 +1947,28 @@ To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\
   (interactive)
   (bookmark-bmenu-delete)
   (forward-line -2)
-  (if (bookmark-bmenu-check-position)
-      (forward-line 1))
-  (bookmark-bmenu-check-position))
+  (bookmark-bmenu-ensure-position)
+  (forward-line 1)
+  (bookmark-bmenu-ensure-position))
 
 
 (defun bookmark-bmenu-execute-deletions ()
-  "Delete bookmarks marked with \\<Buffer-menu-mode-map>\\[Buffer-menu-delete] commands."
+  "Delete bookmarks flagged `D'."
   (interactive)
   (message "Deleting bookmarks...")
-  (let ((hide-em bookmark-bmenu-toggle-filenames)
-        (o-point  (point))
+  (let ((o-point  (point))
         (o-str    (save-excursion
                     (beginning-of-line)
-                    (if (looking-at "^D")
-                        nil
+                    (unless (looking-at "^D")
                       (buffer-substring
                        (point)
                        (progn (end-of-line) (point))))))
         (o-col     (current-column)))
-    (if hide-em (bookmark-bmenu-hide-filenames))
-    (setq bookmark-bmenu-toggle-filenames nil)
     (goto-char (point-min))
     (forward-line 1)
     (while (re-search-forward "^D" (point-max) t)
       (bookmark-delete (bookmark-bmenu-bookmark) t)) ; pass BATCH arg
     (bookmark-bmenu-list)
-    (setq bookmark-bmenu-toggle-filenames hide-em)
-    (if bookmark-bmenu-toggle-filenames
-        (bookmark-bmenu-toggle-filenames t))
     (if o-str
         (progn
           (goto-char (point-min))
@@ -2058,29 +1984,26 @@ To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\
 (defun bookmark-bmenu-rename ()
   "Rename bookmark on current line.  Prompts for a new name."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (let ((bmrk (bookmark-bmenu-bookmark))
-            (thispoint (point)))
-        (bookmark-rename bmrk)
-        (goto-char thispoint))))
+  (let ((bmrk (bookmark-bmenu-bookmark))
+        (thispoint (point)))
+    (bookmark-rename bmrk)
+    (goto-char thispoint)))
 
 
 (defun bookmark-bmenu-locate ()
   "Display location of this bookmark.  Displays in the minibuffer."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (let ((bmrk (bookmark-bmenu-bookmark)))
-        (message "%s" (bookmark-location bmrk)))))
+  (let ((bmrk (bookmark-bmenu-bookmark)))
+    (message "%s" (bookmark-location bmrk))))
 
 (defun bookmark-bmenu-relocate ()
   "Change the file path of the bookmark on the current line,
   prompting with completion for the new path."
   (interactive)
-  (if (bookmark-bmenu-check-position)
-      (let ((bmrk (bookmark-bmenu-bookmark))
-            (thispoint (point)))
-        (bookmark-relocate bmrk)
-        (goto-char thispoint))))
+  (let ((bmrk (bookmark-bmenu-bookmark))
+        (thispoint (point)))
+    (bookmark-relocate bmrk)
+    (goto-char thispoint)))
 
 ;;; Bookmark-bmenu search
 
@@ -2094,11 +2017,11 @@ To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\
         (tmp-list     ()))
     (while
         (let ((char (read-key (concat prompt bookmark-search-pattern))))
-          (case char
-            ((?\e ?\r) nil) ; RET or ESC break the search loop.
+          (pcase char
+            ((or ?\e ?\r) nil) ; RET or ESC break the search loop.
             (?\C-g (setq bookmark-quit-flag t) nil)
             (?\d (pop tmp-list) t) ; Delete last char of pattern with DEL
-            (t
+            (_
              (if (characterp char)
                  (push char tmp-list)
                (setq unread-command-events
@@ -2113,9 +2036,9 @@ To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\
 (defun bookmark-bmenu-filter-alist-by-regexp (regexp)
   "Filter `bookmark-alist' with bookmarks matching REGEXP and rebuild list."
   (let ((bookmark-alist
-         (loop for i in bookmark-alist
-               when (string-match regexp (car i)) collect i into new
-               finally return new)))
+         (cl-loop for i in bookmark-alist
+                  when (string-match regexp (car i)) collect i into new
+                  finally return new)))
     (bookmark-bmenu-list)))
 
 
@@ -2133,18 +2056,18 @@ To carry out the deletions that you've marked, use \\<bookmark-bmenu-mode-map>\\
     (unwind-protect
         (bookmark-read-search-input)
       (cancel-timer timer)
+      (message nil)
       (when bookmark-quit-flag        ; C-g hit restore menu list.
         (bookmark-bmenu-list) (bookmark-bmenu-goto-bookmark bmk))
       (setq bookmark-quit-flag nil))))
-      
+
 (defun bookmark-bmenu-goto-bookmark (name)
   "Move point to bookmark with name NAME."
   (goto-char (point-min))
-  (bookmark-bmenu-check-position)
   (while (not (equal name (bookmark-bmenu-bookmark)))
     (forward-line 1))
   (forward-line 0))
-          
+
 
 \f
 ;;; Menu bar stuff.  Prefix is "bookmark-menu".
@@ -2194,36 +2117,36 @@ strings returned are not."
 ;;;###autoload
 (defvar menu-bar-bookmark-map
   (let ((map (make-sparse-keymap "Bookmark functions")))
-    (define-key map [load]
-      `(menu-item ,(purecopy "Load a Bookmark File...") bookmark-load
-                 :help ,(purecopy "Load bookmarks from a bookmark file)")))
-    (define-key map [write]
-      `(menu-item ,(purecopy "Save Bookmarks As...") bookmark-write
-                 :help ,(purecopy "Write bookmarks to a file (reading the file name with the minibuffer)")))
-    (define-key map [save]
-      `(menu-item ,(purecopy "Save Bookmarks") bookmark-save
-                 :help ,(purecopy "Save currently defined bookmarks")))
-    (define-key map [edit]
-      `(menu-item ,(purecopy "Edit Bookmark List") bookmark-bmenu-list
-                 :help ,(purecopy "Display a list of existing bookmarks")))
-    (define-key map [delete]
-      `(menu-item ,(purecopy "Delete Bookmark...") bookmark-delete
-                 :help ,(purecopy "Delete a bookmark from the bookmark list")))
-    (define-key map [rename]
-      `(menu-item ,(purecopy "Rename Bookmark...") bookmark-rename
-                 :help ,(purecopy "Change the name of a bookmark")))
-    (define-key map [locate]
-      `(menu-item ,(purecopy "Insert Location...") bookmark-locate
-                 :help ,(purecopy "Insert the name of the file associated with a bookmark")))
-    (define-key map [insert]
-      `(menu-item ,(purecopy "Insert Contents...") bookmark-insert
-                 :help ,(purecopy "Insert the text of the file pointed to by a bookmark")))
-    (define-key map [set]
-      `(menu-item ,(purecopy "Set Bookmark...") bookmark-set
-                 :help ,(purecopy "Set a bookmark named inside a file.")))
-    (define-key map [jump]
-      `(menu-item ,(purecopy "Jump to Bookmark...") bookmark-jump
-                 :help ,(purecopy "Jump to a bookmark (a point in some file)")))
+    (bindings--define-key map [load]
+      '(menu-item "Load a Bookmark File..." bookmark-load
+                 :help "Load bookmarks from a bookmark file)"))
+    (bindings--define-key map [write]
+      '(menu-item "Save Bookmarks As..." bookmark-write
+                 :help "Write bookmarks to a file (reading the file name with the minibuffer)"))
+    (bindings--define-key map [save]
+      '(menu-item "Save Bookmarks" bookmark-save
+                 :help "Save currently defined bookmarks"))
+    (bindings--define-key map [edit]
+      '(menu-item "Edit Bookmark List" bookmark-bmenu-list
+                 :help "Display a list of existing bookmarks"))
+    (bindings--define-key map [delete]
+      '(menu-item "Delete Bookmark..." bookmark-delete
+                 :help "Delete a bookmark from the bookmark list"))
+    (bindings--define-key map [rename]
+      '(menu-item "Rename Bookmark..." bookmark-rename
+                 :help "Change the name of a bookmark"))
+    (bindings--define-key map [locate]
+      '(menu-item "Insert Location..." bookmark-locate
+                 :help "Insert the name of the file associated with a bookmark"))
+    (bindings--define-key map [insert]
+      '(menu-item "Insert Contents..." bookmark-insert
+                 :help "Insert the text of the file pointed to by a bookmark"))
+    (bindings--define-key map [set]
+      '(menu-item "Set Bookmark..." bookmark-set
+                 :help "Set a bookmark named inside a file."))
+    (bindings--define-key map [jump]
+      '(menu-item "Jump to Bookmark..." bookmark-jump
+                 :help "Jump to a bookmark (a point in some file)"))
     map))
 
 ;;;###autoload
@@ -2240,14 +2163,14 @@ strings returned are not."
 \f
 ;; Load Hook
 (defvar bookmark-load-hook nil
-  "Hook run at the end of loading bookmark.")
+  "Hook run at the end of loading library `bookmark.el'.")
 
 ;; Exit Hook, called from kill-emacs-hook
+(define-obsolete-variable-alias 'bookmark-exit-hooks
+  'bookmark-exit-hook "22.1")
 (defvar bookmark-exit-hook nil
   "Hook run when Emacs exits.")
 
-(define-obsolete-variable-alias 'bookmark-exit-hooks 'bookmark-exit-hook "22.1")
-
 (defun bookmark-exit-hook-internal ()
   "Save bookmark state, if necessary, at Emacs exit time.
 This also runs `bookmark-exit-hook'."
@@ -2256,7 +2179,8 @@ This also runs `bookmark-exit-hook'."
        (bookmark-time-to-save-p t)
        (bookmark-save)))
 
-(add-hook 'kill-emacs-hook 'bookmark-exit-hook-internal)
+(unless noninteractive
+  (add-hook 'kill-emacs-hook 'bookmark-exit-hook-internal))
 
 (defun bookmark-unload-function ()
   "Unload the Bookmark library."
@@ -2269,5 +2193,4 @@ This also runs `bookmark-exit-hook'."
 
 (provide 'bookmark)
 
-;; arch-tag: 139f519a-dd0c-4b8d-8b5d-f9fcf53ca8f6
 ;;; bookmark.el ends here