-;;; bookmark.el --- set bookmarks, maybe annotate them, jump to them later.
+;;; bookmark.el --- set bookmarks, maybe annotate them, jump to them later
-;; Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation
+;; Copyright (C) 1993, 1994, 1995, 1996, 1997, 2001 Free Software Foundation
;; Author: Karl Fogel <kfogel@red-bean.com>
;; Maintainer: Karl Fogel <kfogel@red-bean.com>
;; Enough with the credits already, get on to the good stuff:
-;; FAVORITE CHINESE RESTAURANT:
+;; 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:
+;;; Code:
(require 'pp)
;;; Misc comments:
;;
;; If variable bookmark-use-annotations is non-nil, an annotation is
-;; queried for when setting a bookmark.
+;; queried for when setting a bookmark.
;;
;; 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
To specify the file in which to save them, modify the variable
`bookmark-default-file', which is `~/.emacs.bmk' by default."
- :type '(choice (const nil) (const t) integer)
+ :type '(choice (const nil) integer (other t))
:group 'bookmark)
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'."
- :type '(choice (const t) (const nil) (const never) (const nospecial))
+ :type '(choice (const nil) (const never) (const nospecial)
+ (other t))
:group 'bookmark)
(defcustom bookmark-automatically-show-annotations t
- "*Nil means don't show annotations when jumping to a bookmark."
+ "*nil means don't show annotations when jumping to a bookmark."
:type 'boolean
:group 'bookmark)
;; This variable is probably obsolete now...
(or (boundp 'baud-rate)
- ;; some random value higher than 9600
+ ;; some random value higher than 9600
(setq baud-rate 19200))
-;; XEmacs apparently call this `buffer-substring-without-properties',
-;; sigh.
-(or (fboundp 'buffer-substring-no-properties)
- (if (fboundp 'buffer-substring-without-properties)
- (fset 'buffer-substring-no-properties
- 'buffer-substring-without-properties)
- (fset 'buffer-substring-no-properties 'buffer-substring)))
\f
;;; Keymap stuff:
(defvar bookmarks-already-loaded nil)
-;; 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.
-;;;###autoload
-(add-hook 'kill-emacs-hook
- (function
- (lambda () (and (featurep 'bookmark)
- bookmark-alist
- (bookmark-time-to-save-p t)
- (bookmark-save)))))
-
;; more stuff added by db.
-(defvar bookmark-current-bookmark nil
+(defvar bookmark-current-bookmark nil
"Name of bookmark most recently used in the current file.
It is buffer local, used to make moving a bookmark forward
through a file easier.")
(defun bookmark-get-bookmark (bookmark)
- "Return the full entry for BOOKMARK in bookmark-alist."
- (assoc bookmark bookmark-alist))
+ "Return the full entry for BOOKMARK in bookmark-alist.
+If BOOKMARK is not a string, return nil."
+ (when (stringp bookmark)
+ (apply (if bookmark-completion-ignore-case
+ #'assoc-ignore-case
+ #'assoc)
+ (list bookmark bookmark-alist))))
(defun bookmark-get-bookmark-record (bookmark)
(defun bookmark-get-info-node (bookmark)
"Get the info node associated with BOOKMARK."
(cdr (assq 'info-node (bookmark-get-bookmark-record bookmark))))
-
+
(defun bookmark-set-info-node (bookmark node)
"Set the Info node of BOOKMARK to NODE."
(message "%S" (assq 'info-node (bookmark-get-bookmark-record bookmark)))
(sit-for 4)
)
-
+
(defvar bookmark-history nil
"The history list for bookmark functions.")
"Put STRING into the bookmark prompt history, if caller non-interactive.
We need this because sometimes bookmark functions are invoked from
menus, so `completing-read' never gets a chance to set `bookmark-history'."
- (` (or
- (interactive-p)
- (setq bookmark-history (cons (, string) bookmark-history)))))
+ `(or
+ (interactive-p)
+ (setq bookmark-history (cons ,string bookmark-history))))
(defun bookmark-make (name &optional annotation overwrite info-node)
;; no prefix arg means just overwrite old bookmark
(setcdr (bookmark-get-bookmark stripped-name)
(list (bookmark-make-cell annotation info-node)))
-
+
;; 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 stripped-name
+ (list stripped-name
(bookmark-make-cell annotation info-node))
bookmark-alist)))
-
+
;; Added by db
(setq bookmark-current-bookmark stripped-name)
(setq bookmark-alist-modification-count
Optional second arg INFO-NODE means this bookmark is at info node
INFO-NODE, so record this fact in the bookmark's entry."
(let ((the-record
- (` ((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)))
- ))))
+ `((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)))))
;; Now fill in the optional parts:
;; Finally, return the completed record.
the-record))
-
-
+
+
\f
;;; File format stuff
;; risk of interfering with existing ones.
;;
;; BOOKMARK-NAME is the string the user gives the bookmark and
-;; accesses it by from then on.
+;; 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 at which the bookmark is set.
;;
-;; STRING-BEHIND is the same thing, but after the point.
+;; STRING-BEHIND is the same thing, but after the point.
;;
;; The context strings exist so that modifications to a file don't
-;; necessarily cause a bookmark's position to be invalidated.
+;; necessarily cause a bookmark's position to be invalidated.
;; 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.
(ann (nth 4 record)))
(list
name
- (` ((filename . (, filename))
- (front-context-string . (, (or front-str "")))
- (rear-context-string . (, (or rear-str "")))
- (position . (, position))
- (annotation . (, ann)))))))
+ `((filename . ,filename)
+ (front-context-string . ,(or front-str ""))
+ (rear-context-string . ,(or rear-str ""))
+ (position . ,position)
+ (annotation . ,ann)))))
old-list))
now-map))))
(annotation nil))
(and (string-equal str "") (setq str default))
- ;; Ask for an annotation buffer for this bookmark
+ ;; Ask for an annotation buffer for this bookmark
(if bookmark-use-annotations
(bookmark-read-annotation parg str)
(bookmark-make str annotation parg (bookmark-info-current-node))
;; Actually, bookmark-make-cell should probably be re-written,
;; to avoid this need. Should I handle the error if a buffer is
;; killed between "C-x r m" and a "C-c C-c" in the annotation buffer?
- (save-excursion
+ (save-excursion
(pop-to-buffer buf)
(goto-char pt)
(bookmark-make bookmark annotation parg (bookmark-info-current-node))
(expand-file-name bookmark-default-file)))
;; return t so the `and' will continue...
t)
-
+
(file-readable-p (expand-file-name bookmark-default-file))
(bookmark-load bookmark-default-file t t)
(setq bookmarks-already-loaded t)))
;;;###autoload
(defun bookmark-jump (bookmark)
- "Jump to bookmark BOOKMARK (a point in some file).
+ "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
(bookmark-show-annotation bookmark)))))
+(defun bookmark-file-or-variation-thereof (file)
+ "Return FILE (a string) if it exists in any reasonable variation, else nil.
+Reasonable variations are FILE.gz, FILE.Z, FILE.info, FILE.info.gz, etc."
+ (cond
+ ((file-exists-p file) file)
+ ((file-exists-p (concat file ".Z")) (concat file ".Z"))
+ ((file-exists-p (concat file ".gz")) (concat file ".gz"))
+ ((file-exists-p (concat file ".z")) (concat file ".z"))
+ ((file-exists-p (concat file ".info")) (concat file ".info"))
+ ((file-exists-p (concat file ".info.gz")) (concat file ".info.gz"))
+ ((file-exists-p (concat file ".info.Z")) (concat file ".info.Z"))
+ ((file-exists-p (concat file ".info.z")) (concat file ".info.z"))
+ ((vc-backend file) file) ; maybe VC has it?
+ (t nil)))
+
+
(defun bookmark-jump-noselect (str)
;; a leetle helper for bookmark-jump :-)
;; returns (BUFFER . POINT)
(info-node (bookmark-get-info-node str))
(orig-file file)
)
- (if (or
- (file-exists-p file)
- ;; else try some common compression extensions
- ;; and Emacs better handle it right!
- ;; Sigh: I think it may *not* be handled at the moment. What
- ;; to do about this?
- (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)))))
+ (if (setq file (bookmark-file-or-variation-thereof file))
(save-excursion
- (if info-node
- ;; Info nodes must be visited with care.
- (progn
- (require 'info)
- (Info-find-node file info-node))
- ;; Else no Info. Can do an ordinary find-file:
- (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)
- (goto-char (match-beginning 0))))
- (if behind-str
- (if (search-backward behind-str (point-min) t)
- (goto-char (match-end 0))))
- ;; added by db
- (setq bookmark-current-bookmark str)
- (cons (current-buffer) (point)))
+ (save-window-excursion
+ (if info-node
+ ;; Info nodes must be visited with care.
+ (progn
+ (require 'info)
+ (Info-find-node file info-node))
+ ;; Else no Info. Can do an ordinary find-file:
+ (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)
+ (goto-char (match-beginning 0))))
+ (if behind-str
+ (if (search-backward behind-str (point-min) t)
+ (goto-char (match-end 0))))
+ ;; added by db
+ (setq bookmark-current-bookmark str)
+ (cons (current-buffer) (point))))
+
;; Else unable to find the marked file, so ask if user wants to
;; relocate the bookmark, else remind them to consider deletion.
(ding)
(bookmark-relocate str)
;; gasp! It's a recursive function call in Emacs Lisp!
(bookmark-jump-noselect str))
- (message
+ (message
"Bookmark not relocated; consider removing it \(%s\)." str)
nil))))
(let ((start (point)))
(prog1
(insert (bookmark-location bookmark)) ; *Return this line*
- (if window-system
- (put-text-property start
- (save-excursion (re-search-backward
- "[^ \t]")
- (1+ (point)))
- 'mouse-face 'highlight)))))
+ (if (and (display-color-p) (display-mouse-p))
+ (add-text-properties start
+ (save-excursion (re-search-backward
+ "[^ \t]")
+ (1+ (point)))
+ '(mouse-face highlight
+ help-echo "mouse-2: go to this bookmark"))))))
;;;###autoload
(defalias 'bookmark-locate 'bookmark-insert-location)
;;;###autoload
(defun bookmark-insert (bookmark)
- "Insert the text of the file pointed to by bookmark BOOKMARK.
+ "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
;;;###autoload
(defun bookmark-delete (bookmark &optional batch)
- "Delete BOOKMARK from the bookmark list.
+ "Delete BOOKMARK 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
;; 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
+ (cond (last-time
(and (> bookmark-alist-modification-count 0)
bookmark-save-flag))
((numberp bookmark-save-flag)
;;;###autoload
-(defun bookmark-save (&optional parg file)
+(defun bookmark-save (&optional parg file)
"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
(set-buffer (let ((enable-local-variables nil))
(find-file-noselect file)))
(goto-char (point-min))
- (delete-region (point-min) (point-max))
- (bookmark-insert-file-format-version-stamp)
- (pp 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))
- (if (>= baud-rate 9600)
- (message "Saving bookmarks to file %s...done" file))
- ))))
+ (let ((print-length nil)
+ (print-level nil))
+ (delete-region (point-min) (point-max))
+ (bookmark-insert-file-format-version-stamp)
+ (pp 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))
+ (if (>= baud-rate 9600)
+ (message "Saving bookmarks to file %s...done" file)))))))
(defun bookmark-import-new-list (new-list)
(interactive
(list (read-file-name
(format "Load bookmarks from: (%s) "
- bookmark-default-file)
+ bookmark-default-file)
;;Default might not be used often,
;;but there's no better default, and
;;I guess it's better than none at all.
(expand-file-name bookmark-default-file)
file)
(setq bookmarks-already-loaded t))
- (bookmark-bmenu-surreptitiously-rebuild-list))
+ (bookmark-bmenu-surreptitiously-rebuild-list))
(error "Invalid bookmark list in %s" file)))
(kill-buffer (current-buffer)))
(if (and (null no-msg) (>= baud-rate 9600))
(define-key bookmark-bmenu-mode-map "j" 'bookmark-bmenu-this-window)
(define-key bookmark-bmenu-mode-map "\C-c\C-c" 'bookmark-bmenu-this-window)
(define-key bookmark-bmenu-mode-map "f" 'bookmark-bmenu-this-window)
+ (define-key bookmark-bmenu-mode-map "\C-m" 'bookmark-bmenu-this-window)
(define-key bookmark-bmenu-mode-map "o" 'bookmark-bmenu-other-window)
(define-key bookmark-bmenu-mode-map "\C-o"
'bookmark-bmenu-switch-other-window)
(define-key bookmark-bmenu-mode-map "?" 'describe-mode)
(define-key bookmark-bmenu-mode-map "u" 'bookmark-bmenu-unmark)
(define-key bookmark-bmenu-mode-map "m" 'bookmark-bmenu-mark)
- (define-key bookmark-bmenu-mode-map "l" 'bookmark-bmenu-load)
+ (define-key bookmark-bmenu-mode-map "l" 'bookmark-bmenu-load)
(define-key bookmark-bmenu-mode-map "r" 'bookmark-bmenu-rename)
(define-key bookmark-bmenu-mode-map "t" 'bookmark-bmenu-toggle-filenames)
(define-key bookmark-bmenu-mode-map "a" 'bookmark-bmenu-show-annotation)
(define-key bookmark-bmenu-mode-map [mouse-2]
'bookmark-bmenu-other-window-with-mouse))
-
+
;; Bookmark Buffer Menu mode is suitable only for specially formatted
;; data.
;; todo: need to display whether or not bookmark exists as a buffer in
-;; flag column.
+;; flag column.
;; Format:
;; FLAGS BOOKMARK [ LOCATION ]
Don't affect the buffer ring order."
(if (get-buffer "*Bookmark List*")
(save-excursion
- (save-window-excursion
+ (save-window-excursion
(bookmark-bmenu-list)))))
(insert " "))
(let ((start (point)))
(insert (bookmark-name-from-full-record full-record))
- (if window-system
- (put-text-property start
- (save-excursion (re-search-backward
- "[^ \t]")
- (1+ (point)))
- 'mouse-face 'highlight))
+ (if (and (display-color-p) (display-mouse-p))
+ (add-text-properties start
+ (save-excursion (re-search-backward
+ "[^ \t]")
+ (1+ (point)))
+ '(mouse-face highlight
+ help-echo "mouse-2: go to this bookmark")))
(insert "\n")
)))
bookmark-alist))
\\[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-rename] -- rename this bookmark \(prompts for new name\).
\\[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-delete-backwards] -- mark this bookmark to be deleted, and move up.
\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[bookmark-bmenu-delete]'.
\\[bookmark-bmenu-save] -- save the current bookmark list in the default file.
With a prefix arg, prompts for a file to save in.
(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 window-system
+ (if (and (display-color-p) (display-mouse-p))
(remove-text-properties start (point)
- '(mouse-face))))
+ '(mouse-face nil help-echo nil))))
(delete-region (point) (progn (end-of-line) (point)))
(insert " ")
;; Pass the NO-HISTORY arg:
(bookmark-kill-line)
(let ((start (point)))
(insert (car bookmark-bmenu-hidden-bookmarks))
- (if window-system
- (put-text-property start
- (save-excursion (re-search-backward
- "[^ \t]")
- (1+ (point)))
- 'mouse-face 'highlight)))
+ (if (and (display-color-p) (display-mouse-p))
+ (add-text-properties start
+ (save-excursion (re-search-backward
+ "[^ \t]")
+ (1+ (point)))
+ '(mouse-face highlight
+ help-echo
+ "mouse-2: go to this bookmark"))))
(setq bookmark-bmenu-hidden-bookmarks
(cdr bookmark-bmenu-hidden-bookmarks))
(forward-line 1))))))))
(beginning-of-line)
(forward-char bookmark-bmenu-bookmark-column)
(prog1
- (buffer-substring-no-properties (point)
- (progn
+ (buffer-substring-no-properties (point)
+ (progn
(end-of-line)
(point)))
;; well, this is certainly crystal-clear:
(interactive)
(if (bookmark-bmenu-check-position)
(let ((bmrk (bookmark-bmenu-bookmark))
- (menu (current-buffer))
+ (menu (current-buffer))
(others ())
tem)
(goto-char (point-min))
(let ((buffer-read-only nil))
(delete-char -1)
(insert ?\ ))
- (or (string-equal tem bmrk)
- (member tem others)
+ (or (string-equal tem bmrk)
+ (member tem others)
(setq others (cons tem others))))
(setq others (nreverse others)
tem (/ (1- (frame-height)) (1+ (length others))))
"Make the other window select this line's bookmark.
The current window remains selected."
(interactive)
- (let ((bookmark (bookmark-bmenu-bookmark)))
+ (let ((bookmark (bookmark-bmenu-bookmark))
+ (pop-up-windows t)
+ same-window-buffer-names
+ same-window-regexps)
(if (bookmark-bmenu-check-position)
(let* ((pair (bookmark-jump-noselect bookmark))
(buff (car pair))
;;;###autoload
(defun bookmark-menu-insert (event)
- "Insert the text of the file pointed to by bookmark BOOKMARK.
+ "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
;;;###autoload
(defun bookmark-menu-jump (event)
- "Jump to bookmark BOOKMARK (a point in some file).
+ "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
;;;###autoload
(defun bookmark-menu-locate (event)
- "Insert the name of the file associated with BOOKMARK.
+ "Insert the name of the file associated with BOOKMARK.
\(This is not the same as the contents of that file\).
Warning: this function only takes an EVENT as argument. Use the
;;;###autoload
(defun bookmark-menu-rename (event)
- "Change the name of OLD-BOOKMARK to NEWNAME.
+ "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.
+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.
;;;###autoload
(defun bookmark-menu-delete (event)
- "Delete the bookmark named NAME from the bookmark list.
+ "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
;; make bookmarks appear toward the right side of the menu.
(if (boundp 'menu-bar-final-items)
- (if 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)))
'("Set Bookmark" . bookmark-set))
;;;###autoload
-(define-key menu-bar-bookmark-map [jump]
+(define-key menu-bar-bookmark-map [jump]
'("Jump to Bookmark" . bookmark-menu-jump))
;;;; end bookmark menu stuff ;;;;
(defvar bookmark-load-hook nil
"Hook to run at the end of loading bookmark.")
+;;; Exit Hook, called from kill-emacs-hook
+(defvar bookmark-exit-hook nil
+ "Hook to run when emacs exits")
+
+(defun bookmark-exit-hook-internal ()
+ "Save bookmark state, if necessary, at Emacs exit time.
+This also runs `bookmark-exit-hooks'."
+ (and
+ (progn (run-hooks 'bookmark-exit-hooks) t)
+ bookmark-alist
+ (bookmark-time-to-save-p t)
+ (bookmark-save)))
+
+(add-hook 'kill-emacs-hook 'bookmark-exit-hook-internal)
+
+
(run-hooks 'bookmark-load-hook)
(provide 'bookmark)
-
+
;;; bookmark.el ends here