X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/cfa8348f2b4afe1df779619762e8483472055604..2d0ffc9aa8662ec6d931bcb0d755ceb36fc62020:/lisp/bookmark.el diff --git a/lisp/bookmark.el b/lisp/bookmark.el index e8bbd30b9b..ec5a4f590f 100644 --- a/lisp/bookmark.el +++ b/lisp/bookmark.el @@ -1,12 +1,11 @@ -;;; bookmark.el --- set bookmarks, jump to them later. +;;; bookmark.el --- set bookmarks, maybe annotate them, jump to them later. -;; Copyright (C) 1993, 1994 Free Software Foundation +;; Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation -;; Author: Karl Fogel -;; Maintainer: Karl Fogel +;; Author: Karl Fogel +;; Maintainer: Karl Fogel ;; Created: July, 1993 -;; Version: 2.5 -;; Keywords: bookmarks, placeholders +;; Keywords: bookmarks, placeholders, annotations ;; This file is part of GNU Emacs. @@ -21,8 +20,16 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This package is for setting "bookmarks" in files. A bookmark +;; associates a string with a location in a certain file. Thus, you +;; can navigate your way to that location by providing the string. +;; See the "User Variables" section for customizations. ;; Thanks to David Bremner for thinking of and ;; then implementing the bookmark-current-bookmark idea. He even @@ -31,16 +38,16 @@ ;; Thanks to Gregory M. Saunders for ;; fixing and improving bookmark-time-to-save-p. -;; Thanks go to Andrew V. Klein for the code that -;; sorts the alist before presenting it to the user (in list-bookmarks +;; Thanks go to Andrew V. Klein 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 for many small ;; suggestions and the code to implement them (like -;; Bookmark-menu-check-position, and some of the Lucid compatibility +;; bookmark-bmenu-check-position, and some of the Lucid compatibility ;; stuff). -;; Kudos (whatever they are) go to Jim Blandy +;; Kudos (whatever they are) go to Jim Blandy ;; for his eminently sensible suggestion to separate bookmark-jump ;; into bookmark-jump and bookmark-jump-noselect, which made many ;; other things cleaner as well. @@ -48,72 +55,176 @@ ;; Thanks to Roland McGrath for encouragement and help with defining ;; autoloads on the menu-bar. -;; Jonathan Stigelman gave patches for default +;; Jonathan Stigelman 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 for +;; thinking up the annotations feature and implementing it so well. + ;; Based on info-bookmark.el, by Karl Fogel and Ken Olstad ;; . -;; LCD Archive Entry: -;; bookmark|Karl Fogel|kfogel@cs.oberlin.edu| -;; Setting bookmarks in files or directories, jumping to them later.| -;; 16-July-93|Version: 2.5|~/misc/bookmark.el.Z| +;; Thanks to Mikio Nakajima 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? + +;;;; Code: -;;; Commentary: +(require 'pp) -;; bookmark alist format: -;; (... -;; (bookmark-name (filename -;; string-in-front -;; string-behind -;; point)) -;; ...) +;;; Misc comments: ;; -;; bookmark-name is the string the user gives the bookmark and -;; accesses it by from then on. filename is the location of the file -;; in which the bookmark is set. string-in-front is a string of -;; `bookmark-search-size' chars of context in front of the point the -;; bookmark is set at, string-behind is the same thing after the -;; point. bookmark-jump will search for string-behind and -;; string-in-front in case the file has changed since the bookmark was -;; set. It will attempt to place the user before the changes, if -;; there were any. +;; If variable bookmark-use-annotations is non-nil, an annotation is +;; 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 ;; the list will be presented in the order it is recorded ;; (chronologically), which is actually fairly useful as well. -;;; Code: +;;; User Variables + +(defgroup bookmark nil + "Setting, annotation and jumping to bookmarks." + :group 'matching) + + +(defcustom bookmark-use-annotations nil + "*If non-nil, saving a bookmark queries for an annotation in a buffer." + :type 'boolean + :group 'bookmark) + + +(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]\). +--> 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 + 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.\) + +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) integer (other t)) + :group 'bookmark) + + +(defconst bookmark-old-default-file "~/.emacs-bkmrks" + "*The `.emacs.bmk' file used to be called this name.") + + +;; defvarred to avoid a compilation warning: +(defvar bookmark-file nil + "Old name for `bookmark-default-file'.") + +(defcustom bookmark-default-file + (if bookmark-file + ;; In case user set `bookmark-file' in her .emacs: + bookmark-file + (convert-standard-filename "~/.emacs.bmk")) + "*File in which to save bookmarks by default." + :type 'file + :group 'bookmark) + + +(defcustom bookmark-version-control 'nospecial + "*Whether or not to make numbered backups of the bookmark file. +It can have four values: t, nil, `never', and `nospecial'. +The first three have the same meaning that they do for the +variable `version-control', and the final value `nospecial' means just +use the value of `version-control'." + :type '(choice (const nil) (const never) (const nospecial) + (other t)) + :group 'bookmark) + + +(defcustom bookmark-completion-ignore-case t + "*Non-nil means bookmark functions ignore case in completion." + :type 'boolean + :group 'bookmark) + + +(defcustom bookmark-sort-flag t + "*Non-nil means that bookmarks will be displayed sorted by bookmark name. +Otherwise they will be displayed in LIFO order (that is, most +recently set ones come first, oldest ones come last)." + :type 'boolean + :group 'bookmark) + + +(defcustom bookmark-automatically-show-annotations t + "*Nil means don't show annotations when jumping to a bookmark." + :type 'boolean + :group 'bookmark) + + +(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-toggle-filenames]." + :type 'integer + :group 'bookmark) + + +(defcustom bookmark-bmenu-toggle-filenames t + "*Non-nil means show filenames when listing bookmarks. +This may result in truncated bookmark names. To disable this, put the +following in your `.emacs' file: + +\(setq bookmark-bmenu-toggle-filenames nil\)" + :type 'boolean + :group 'bookmark) + + +(defcustom bookmark-menu-length 70 + "*Maximum length of a bookmark name displayed on a popup menu." + :type 'integer + :group 'boolean) + + +;;; No user-serviceable parts beyond this point. + +;; Is it XEmacs? +(defconst bookmark-xemacsp + (string-match "\\(Lucid\\|Xemacs\\)" emacs-version)) + ;; Added for lucid emacs compatibility, db (or (fboundp 'defalias) (fset 'defalias 'fset)) ;; suggested for lucid compatibility by david hughes: -(or (fboundp 'frame-height) (fset 'frame-height 'screen-height)) +(or (fboundp 'frame-height) (defalias 'frame-height 'screen-height)) -;; some people have C-x r set to rmail or whatever. We don't want to -;; assume that C-x r is a prefix map just because it's distributed -;; that way... -;; These are the distribution keybindings suggested by RMS, everything -;; else will be done with M-x or the menubar: -;;;###autoload -(if (or (symbolp (key-binding "\C-xr")) - (fboundp 'bookmark-set)) - nil - (progn (define-key ctl-x-map "rb" 'bookmark-jump) - (define-key ctl-x-map "rm" 'bookmark-set) - (define-key ctl-x-map "rl" 'list-bookmarks))) +;; This variable is probably obsolete now... +(or (boundp 'baud-rate) + ;; some random value higher than 9600 + (setq baud-rate 19200)) -;; define the map, so it can be bound by those who desire to do so: + + +;;; Keymap stuff: + +;; Set up these bindings dumping time *only*; +;; if the user alters them, don't override the user when loading bookmark.el. + +;;;###autoload (define-key ctl-x-map "rb" 'bookmark-jump) +;;;###autoload (define-key ctl-x-map "rm" 'bookmark-set) +;;;###autoload (define-key ctl-x-map "rl" 'bookmark-bmenu-list) ;;;###autoload (defvar bookmark-map nil @@ -140,7 +251,7 @@ functions have a binding in this keymap.") ;;;###autoload (define-key bookmark-map "e" 'edit-bookmarks) ;;;###autoload -(define-key bookmark-map "f" 'bookmark-locate) ; "f" for "find" +(define-key bookmark-map "f" 'bookmark-insert-location) ; "f" for "find" ;;;###autoload (define-key bookmark-map "r" 'bookmark-rename) ;;;###autoload @@ -152,15 +263,46 @@ functions have a binding in this keymap.") ;;;###autoload (define-key bookmark-map "s" 'bookmark-save) + +;;; The annotation maps. +(defvar bookmark-read-annotation-mode-map (copy-keymap text-mode-map) + "Keymap for composing an annotation for a bookmark.") + +(define-key bookmark-read-annotation-mode-map "\C-c\C-c" + 'bookmark-send-annotation) + + + +;;; Core variables and data structures: (defvar bookmark-alist () - "Association list of bookmarks. + "Association list of bookmarks and their records. You probably don't want to change the value of this alist yourself; -instead, let the various bookmark functions do it for you.") +instead, let the various bookmark functions do it for you. + +The format of the alist is + + \(BOOKMARK1 BOOKMARK2 ...\) + +where each BOOKMARK is of the form + +\(NAME + \(filename . FILE\) + \(front-context-string . FRONT-STR\) + \(rear-context-string . REAR-STR\) + \(position . POS\) + \(info-node . POS\) + \(annotation . ANNOTATION\)\) + +So the cdr of each bookmark is an alist too. +`info-node' is optional, by the way.") + (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) @@ -177,58 +319,426 @@ through a file easier.") (make-variable-buffer-local 'bookmark-current-bookmark) -(defvar 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]\). ---> t means save bookmarks when Emacs is killed. ---> Otherise, it should be a number that is the frequency with which - the bookmark list is saved \(i.e.: the number of times which - Emacs' bookmark list may be modified before it is automatically - saved.\). If it is a number, Emacs will also automatically save - bookmarks when it is killed. - -Therefore, the way to get it to save every time you make or delete a -bookmark is to set this variable to 1 \(or 0, which produces the same -behavior.\) - -To specify the file in which to save them, modify the variable -bookmark-file, which is `~/.emacs-bkmrks' by default.") (defvar bookmark-alist-modification-count 0 "Number of modifications to bookmark list since it was last saved.") -(defvar bookmark-file - (if (or (eq system-type 'ms-dos) (eq system-type 'windows-nt)) - "~/emacs.bmk" ; Cannot have initial dot [Yuck!] - "~/.emacs-bkmrks") - "*File in which to save bookmarks by default.") - -(defvar bookmark-version-control 'nospecial - "Control whether to make numbered backups of the master bookmark file. -This variable can have four values: t, nil, `never', and `nospecial'. -The first three have the same meaning that they do for the -variable `version-control'. -The value `nospecial' means just use the value of `version-control'.") - -(defvar bookmark-completion-ignore-case t - "*Non-nil means bookmark functions ignore case in completion.") - -(defvar bookmark-sort-flag t - "*Non-nil means display bookmarks sorted by name. -Otherwise they are displayed in LIFO order (that is, most -recently set ones come first, oldest ones come last).") -(defvar bookmark-search-size 500 +(defvar bookmark-search-size 16 "Length of the context strings recorded on either side of a bookmark.") + (defvar bookmark-current-point 0) (defvar bookmark-yank-point 0) (defvar bookmark-current-buffer nil) + + +;; Helper functions. + +;; Only functions on 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-all-names () + "Return a list of all current bookmark names." + (bookmark-maybe-load-default-file) + (mapcar + (lambda (full-record) + (bookmark-name-from-full-record full-record)) + bookmark-alist)) + + +(defun bookmark-get-bookmark (bookmark) + "Return the full entry for BOOKMARK in bookmark-alist." + (assoc bookmark bookmark-alist)) + + +(defun bookmark-get-bookmark-record (bookmark) + "Return the guts of the entry for BOOKMARK in bookmark-alist. +That is, all information but the name." + (car (cdr (bookmark-get-bookmark bookmark)))) + + +(defun bookmark-set-name (bookmark newname) + "Set BOOKMARK's name to NEWNAME." + (setcar + (if (stringp bookmark) (bookmark-get-bookmark bookmark) bookmark) + newname)) + + +(defun bookmark-get-annotation (bookmark) + "Return the annotation of BOOKMARK, or nil if none." + (cdr (assq 'annotation (bookmark-get-bookmark-record bookmark)))) + + +(defun bookmark-set-annotation (bookmark ann) + "Set the annotation of BOOKMARK to ANN." + (let ((cell (assq 'annotation (bookmark-get-bookmark-record bookmark)))) + (if cell + (setcdr cell ann) + (nconc (bookmark-get-bookmark-record bookmark) + (list (cons 'annotation ann)))))) + + +(defun bookmark-get-filename (bookmark) + "Return the full filename of BOOKMARK." + (cdr (assq 'filename (bookmark-get-bookmark-record bookmark)))) + + +(defun bookmark-set-filename (bookmark filename) + "Set the full filename of BOOKMARK to FILENAME." + (let ((cell (assq 'filename (bookmark-get-bookmark-record bookmark)))) + (if cell + (setcdr cell filename) + (nconc (bookmark-get-bookmark-record bookmark) + (list (cons 'filename filename)))))) + + +(defun bookmark-get-position (bookmark) + "Return the position \(i.e.: point\) of BOOKMARK." + (cdr (assq 'position (bookmark-get-bookmark-record bookmark)))) + + +(defun bookmark-set-position (bookmark position) + "Set the position \(i.e.: point\) of BOOKMARK to POSITION." + (let ((cell (assq 'position (bookmark-get-bookmark-record bookmark)))) + (if cell + (setcdr cell position) + (nconc (bookmark-get-bookmark-record bookmark) + (list (cons 'position position)))))) + + +(defun bookmark-get-front-context-string (bookmark) + "Return the front-context-string of BOOKMARK." + (cdr (assq 'front-context-string (bookmark-get-bookmark-record bookmark)))) + + +(defun bookmark-set-front-context-string (bookmark string) + "Set the front-context-string of BOOKMARK to STRING." + (let ((cell (assq 'front-context-string + (bookmark-get-bookmark-record bookmark)))) + (if cell + (setcdr cell string) + (nconc (bookmark-get-bookmark-record bookmark) + (list (cons 'front-context-string string)))))) + + +(defun bookmark-get-rear-context-string (bookmark) + "Return the rear-context-string of BOOKMARK." + (cdr (assq 'rear-context-string (bookmark-get-bookmark-record bookmark)))) + + +(defun bookmark-set-rear-context-string (bookmark string) + "Set the rear-context-string of BOOKMARK to STRING." + (let ((cell (assq 'rear-context-string + (bookmark-get-bookmark-record bookmark)))) + (if cell + (setcdr cell string) + (nconc (bookmark-get-bookmark-record bookmark) + (list (cons 'rear-context-string string)))))) + + +(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." + (let ((cell (assq 'info-node + (bookmark-get-bookmark-record bookmark)))) + (if cell + (setcdr cell node) + (nconc (bookmark-get-bookmark-record bookmark) + (list (cons 'info-node node))))) + + (message "%S" (assq 'info-node (bookmark-get-bookmark-record bookmark))) + (sit-for 4) + ) + + +(defvar bookmark-history nil + "The history list for bookmark functions.") + + +(defun bookmark-completing-read (prompt &optional default) + "Prompting with PROMPT, read a bookmark name in completion. +PROMPT will get a \": \" stuck on the end no matter what, so you +probably don't want to include one yourself. +Optional second arg DEFAULT is a string to return if the user enters +the empty string." + (bookmark-maybe-load-default-file) ; paranoia + (let* ((completion-ignore-case bookmark-completion-ignore-case) + (default default) + (prompt (if default + (concat prompt (format " (%s): " default)) + (concat prompt ": "))) + (str + (completing-read prompt + bookmark-alist + nil + 0 + nil + 'bookmark-history))) + (if (string-equal "" str) + (list default) + (list str)))) + + +(defmacro bookmark-maybe-historicize-string (string) + "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))))) + + +(defun bookmark-make (name &optional annotation overwrite info-node) + "Make a bookmark named NAME. +Optional second arg ANNOTATION gives it an annotation. +Optional third arg OVERWRITE means replace any existing bookmarks with +this name. +Optional fourth arg INFO-NODE means this bookmark is at info node +INFO-NODE, so record this fact in the bookmark's entry." + (bookmark-maybe-load-default-file) + (let ((stripped-name (copy-sequence name))) + (or bookmark-xemacsp + ;; XEmacs's `set-text-properties' doesn't work on + ;; free-standing strings, apparently. + (set-text-properties 0 (length stripped-name) nil stripped-name)) + (if (and (bookmark-get-bookmark stripped-name) (not overwrite)) + ;; already existing bookmark under that name and + ;; 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 + (bookmark-make-cell annotation info-node)) + bookmark-alist))) + + ;; Added by db + (setq bookmark-current-bookmark stripped-name) + (setq bookmark-alist-modification-count + (1+ bookmark-alist-modification-count)) + (if (bookmark-time-to-save-p) + (bookmark-save)))) + + +(defun bookmark-make-cell (annotation &optional info-node) + "Return the record part of a new bookmark, given ANNOTATION. +Must be at the correct position in the buffer in which the bookmark is +being set. This might change someday. +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))) + )))) + + ;; Now fill in the optional parts: + + ;; Take no chances with text properties + (set-text-properties 0 (length annotation) nil annotation) + (set-text-properties 0 (length info-node) nil info-node) + + (if annotation + (nconc the-record (list (cons 'annotation annotation)))) + (if info-node + (nconc the-record (list (cons 'info-node info-node)))) + + ;; Finally, return the completed record. + the-record)) + + + +;;; File format stuff + +;; The OLD format of the bookmark-alist was: +;; +;; ((bookmark-name (filename +;; string-in-front +;; string-behind +;; point)) +;; ...) +;; +;; The NEW format of the bookmark-alist is: +;; +;; ((bookmark-name ((filename . FILENAME) +;; (front-context-string . string-in-front) +;; (rear-context-string . string-behind) +;; (position . POINT) +;; (annotation . annotation) +;; (whatever . VALUE) +;; ... +;; )) +;; ...) +;; +;; +;; I switched to using an internal as well as external alist because I +;; felt that would be a more flexible framework in which to add +;; features. It means that the order in which values appear doesn't +;; matter, and it means that arbitrary values can be added without +;; risk of interfering with existing ones. +;; +;; BOOKMARK-NAME is the string the user gives the bookmark and +;; accesses it by from then on. +;; +;; FILENAME is the location of the file in which the bookmark is set. +;; +;; STRING-IN-FRONT is a string of `bookmark-search-size' chars of +;; context in front of the point at which the bookmark is set. +;; +;; 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. +;; 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. +;; ANNOTATION is the annotation for the bookmark; it may not exist +;; (for backward compatibility), be nil (no annotation), or be a +;; string. + + +(defconst bookmark-file-format-version 1 + "The current version of the format used by bookmark files. +You should never need to change this.") + + +(defconst bookmark-end-of-version-stamp-marker + "-*- End Of Bookmark File Format Version Stamp -*-\n" + "This string marks the end of the version stamp in a bookmark file.") + + +(defun bookmark-alist-from-buffer () + "Return a bookmark-alist (in any format) from the current buffer. +The buffer must of course contain bookmark format information. +Does not care from where in the buffer it is called, and does not +affect point." + (save-excursion + (goto-char (point-min)) + (if (search-forward bookmark-end-of-version-stamp-marker nil t) + (read (current-buffer)) + ;; Else we're dealing with format version 0 + (if (search-forward "(" nil t) + (progn + (forward-char -1) + (read (current-buffer))) + ;; Else no hope of getting information here. + (error "Not bookmark format"))))) + + +(defun bookmark-upgrade-version-0-alist (old-list) + "Upgrade a version 0 alist OLD-LIST to the current version." + (mapcar + (lambda (bookmark) + (let* ((name (car bookmark)) + (record (car (cdr bookmark))) + (filename (nth 0 record)) + (front-str (nth 1 record)) + (rear-str (nth 2 record)) + (position (nth 3 record)) + (ann (nth 4 record))) + (list + name + (` ((filename . (, filename)) + (front-context-string . (, (or front-str ""))) + (rear-context-string . (, (or rear-str ""))) + (position . (, position)) + (annotation . (, ann))))))) + old-list)) + + +(defun bookmark-upgrade-file-format-from-0 () + "Upgrade a bookmark file of format 0 (the original format) to format 1. +This expects to be called from point-min in a bookmark file." + (message "Upgrading bookmark format from 0 to %d..." + bookmark-file-format-version) + (let* ((old-list (bookmark-alist-from-buffer)) + (new-list (bookmark-upgrade-version-0-alist old-list))) + (delete-region (point-min) (point-max)) + (bookmark-insert-file-format-version-stamp) + (pp new-list (current-buffer)) + (save-buffer)) + (goto-char (point-min)) + (message "Upgrading bookmark format from 0 to %d...done" + bookmark-file-format-version) + ) + + +(defun bookmark-grok-file-format-version () + "Return an integer which is the file-format version of this bookmark file. +This expects to be called from point-min in a bookmark file." + (if (looking-at "^;;;;") + (save-excursion + (save-match-data + (re-search-forward "[0-9]") + (forward-char -1) + (read (current-buffer)))) + ;; Else this is format version 0, the original one, which didn't + ;; even have version stamps. + 0)) + + +(defun bookmark-maybe-upgrade-file-format () + "Check the file-format version of this bookmark file. +If the version is not up-to-date, upgrade it automatically. +This expects to be called from point-min in a bookmark file." + (let ((version (bookmark-grok-file-format-version))) + (cond + ((= version bookmark-file-format-version) + ) ; home free -- version is current + ((= version 0) + (bookmark-upgrade-file-format-from-0)) + (t + (error "Bookmark file format version strangeness"))))) + + +(defun bookmark-insert-file-format-version-stamp () + "Insert text indicating current version of bookmark file format." + (insert + (format ";;;; Emacs Bookmark Format Version %d ;;;;\n" + bookmark-file-format-version)) + (insert ";;; This format is meant to be slightly human-readable;\n" + ";;; nevertheless, you probably don't want to edit it.\n" + ";;; " + bookmark-end-of-version-stamp-marker)) + + +;;; end file-format stuff + + +;;; Core code: + ;;;###autoload -(defun bookmark-set (&optional parg) - "Set a bookmark named NAME inside the visited file. +(defun bookmark-set (&optional name parg) + "Set a bookmark named NAME inside a file. +If name is nil, then the user will be prompted. With prefix arg, will not overwrite a bookmark that has the same name as NAME if such a bookmark already exists, but instead will \"push\" the new bookmark onto the bookmark alist. Thus the most recently set @@ -240,68 +750,250 @@ To yank words from the text of the buffer and use them as part of the bookmark name, type C-w while setting a bookmark. Successive C-w's yank successive words. -Typing C-v inserts the name of the current file being visited. Typing -C-u inserts the name of the last bookmark used in the buffer \(as an -aid in using a single bookmark name to track your progress through a -large file\). If no bookmark was used, then C-u behaves like C-v and -inserts the name of the file being visited. +Typing C-u inserts the name of the last bookmark used in the buffer +\(as an aid in using a single bookmark name to track your progress +through a large file\). If no bookmark was used, then C-u inserts the +name of the file being visited. Use \\[bookmark-delete] to remove bookmarks \(you give it a name, and it removes only the first instance of a bookmark with that name from the list of bookmarks.\)" - (interactive "P") - (if (not (bookmark-buffer-file-name)) - (error "Buffer not visiting a file or directory.")) - (bookmark-try-default-file) + (interactive (list nil current-prefix-arg)) + (or + (bookmark-buffer-file-name) + (error "Buffer not visiting a file or directory")) + + (bookmark-maybe-load-default-file) + (setq bookmark-current-point (point)) (setq bookmark-yank-point (point)) (setq bookmark-current-buffer (current-buffer)) + (let* ((default (or bookmark-current-bookmark - (buffer-name (current-buffer)))) + (bookmark-buffer-name))) (str - (read-from-minibuffer - (format "Set bookmark (%s): " default) - nil - (let ((now-map (copy-keymap minibuffer-local-map))) - (progn (define-key now-map "\C-w" - 'bookmark-yank-word) - (define-key now-map "\C-v" - 'bookmark-insert-current-file-name) - (define-key now-map "\C-u" - 'bookmark-insert-current-bookmark)) - now-map)))) - (and (string-equal str "") (setq str default)) - (progn - (bookmark-make parg str) + (or name + (read-from-minibuffer + (format "Set bookmark (%s): " default) + nil + (let ((now-map (copy-keymap minibuffer-local-map))) + (define-key now-map "\C-w" 'bookmark-yank-word) + (define-key now-map "\C-u" 'bookmark-insert-current-bookmark) + now-map)))) + (annotation nil)) + (and (string-equal str "") (setq str default)) + ;; 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)) (setq bookmark-current-bookmark str) - (if (get-buffer "*Bookmark List*") ;rebuild the bookmark list - (save-excursion - (save-window-excursion - (list-bookmarks)))) + (bookmark-bmenu-surreptitiously-rebuild-list) (goto-char bookmark-current-point)))) + +(defun bookmark-info-current-node () + "If in Info-mode, return current node name (a string), else nil." + (if (eq major-mode 'Info-mode) + Info-current-node)) + + +(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)))) + (delete-region (point) eol) + (if (and newline-too (looking-at "\n")) + (delete-char 1)))) + + +;; Defvars to avoid compilation warnings: +(defvar bookmark-annotation-paragraph nil) +(defvar bookmark-annotation-name nil) +(defvar bookmark-annotation-buffer nil) +(defvar bookmark-annotation-file nil) +(defvar bookmark-annotation-point nil) + + +(defun bookmark-send-annotation () + "Use buffer contents as the annotation for a bookmark. +Exclude lines that begin with `#'. +Store the annotation text in the bookmark list with +the bookmark (and file, and point) specified in buffer local variables." + (interactive) + (if (not (eq major-mode 'bookmark-read-annotation-mode)) + (error "Not in bookmark-read-annotation-mode")) + (goto-char (point-min)) + (while (< (point) (point-max)) + (if (looking-at "^#") + (bookmark-kill-line t) + (forward-line 1))) + (let ((annotation (buffer-string)) + (parg bookmark-annotation-paragraph) + (bookmark bookmark-annotation-name) + (pt bookmark-annotation-point) + (buf bookmark-annotation-buffer)) + ;; for bookmark-make-cell to work, we need to be + ;; in the relevant buffer, at the relevant point. + ;; 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 + (pop-to-buffer buf) + (goto-char pt) + (bookmark-make bookmark annotation parg (bookmark-info-current-node)) + (setq bookmark-current-bookmark bookmark)) + (bookmark-bmenu-surreptitiously-rebuild-list) + (goto-char bookmark-current-point)) + (kill-buffer (current-buffer))) + + +(defun bookmark-default-annotation-text (bookmark) + (concat "# Type the annotation for bookmark '" bookmark "' 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) "@" + (system-name) ">\n" + "# Date: " (current-time-string) "\n")) + + +(defvar bookmark-read-annotation-text-func 'bookmark-default-annotation-text + "Function to return default text to use for a bookmark annotation. +It takes the name of the bookmark, as a string, as an arg.") + +(defun bookmark-read-annotation-mode (buf point parg bookmark) + "Mode for composing annotations for a bookmark. +Wants BUF POINT PARG and BOOKMARK. +When you have finished composing, type \\[bookmark-send-annotation] to send +the annotation. + +\\{bookmark-read-annotation-mode-map} +" + (interactive) + (kill-all-local-variables) + (make-local-variable 'bookmark-annotation-paragraph) + (make-local-variable 'bookmark-annotation-name) + (make-local-variable 'bookmark-annotation-buffer) + (make-local-variable 'bookmark-annotation-file) + (make-local-variable 'bookmark-annotation-point) + (setq bookmark-annotation-paragraph parg) + (setq bookmark-annotation-name bookmark) + (setq bookmark-annotation-buffer buf) + (setq bookmark-annotation-file (buffer-file-name buf)) + (setq bookmark-annotation-point point) + (use-local-map bookmark-read-annotation-mode-map) + (setq major-mode 'bookmark-read-annotation-mode) + (insert (funcall bookmark-read-annotation-text-func bookmark)) + (run-hooks 'text-mode-hook)) + + +(defun bookmark-read-annotation (parg bookmark) + "Pop up a buffer for entering a bookmark annotation. +Text surrounding the bookmark is PARG; the bookmark name is BOOKMARK." + (let ((buf (current-buffer)) + (point (point))) + (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*")) + (bookmark-read-annotation-mode buf point parg bookmark))) + + +(defvar bookmark-edit-annotation-mode-map (copy-keymap text-mode-map) + "Keymap for editing an annotation of a bookmark.") + + +(define-key bookmark-edit-annotation-mode-map "\C-c\C-c" + 'bookmark-send-edited-annotation) + + +(defun bookmark-edit-annotation-mode (bookmark) + "Mode for editing the annotation of bookmark BOOKMARK. +When you have finished composing, type \\[bookmark-send-annotation]. + +\\{bookmark-edit-annotation-mode-map} +" + (interactive) + (kill-all-local-variables) + (make-local-variable 'bookmark-annotation-name) + (setq bookmark-annotation-name bookmark) + (use-local-map bookmark-edit-annotation-mode-map) + (setq major-mode 'bookmark-edit-annotation-mode) + (insert (funcall bookmark-read-annotation-text-func bookmark)) + (let ((annotation (bookmark-get-annotation bookmark))) + (if (and annotation (not (string-equal annotation ""))) + (insert annotation))) + (run-hooks 'text-mode-hook)) + + +(defun bookmark-send-edited-annotation () + "Use buffer contents (minus beginning with `#' as annotation for a bookmark." + (interactive) + (if (not (eq major-mode 'bookmark-edit-annotation-mode)) + (error "Not in bookmark-edit-annotation-mode")) + (goto-char (point-min)) + (while (< (point) (point-max)) + (if (looking-at "^#") + (bookmark-kill-line t) + (forward-line 1))) + (let ((annotation (buffer-string)) + (bookmark bookmark-annotation-name)) + (bookmark-set-annotation bookmark annotation) + (bookmark-bmenu-surreptitiously-rebuild-list) + (goto-char bookmark-current-point)) + (kill-buffer (current-buffer))) + + +(defun bookmark-edit-annotation (bookmark) + "Pop up a buffer for editing bookmark BOOKMARK's annotation." + (let ((buf (current-buffer)) + (point (point))) + (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*")) + (bookmark-edit-annotation-mode bookmark))) + + (defun bookmark-insert-current-bookmark () - ;; insert this buffer's value of bookmark-current-bookmark, default - ;; to file name if it's nil. + "Insert this buffer's value of bookmark-current-bookmark. +Default to file name if it's nil." (interactive) (let ((str (save-excursion (set-buffer bookmark-current-buffer) bookmark-current-bookmark))) - (if str (insert str) (bookmark-insert-current-file-name)))) + (if str (insert str) (bookmark-insert-buffer-name)))) + -(defun bookmark-insert-current-file-name () - ;; insert the name (sans path) of the current file into the bookmark - ;; name that is being set. +(defun bookmark-insert-buffer-name () + "Insert the current file name into the bookmark name being set. +The directory part of the file name is not used." (interactive) - (let ((str (save-excursion - (set-buffer bookmark-current-buffer) - (bookmark-buffer-file-name)))) - (insert (substring - str - (1+ (string-match - "\\(/[^/]*\\)/*$" - str)))))) + (let ((str + (save-excursion + (set-buffer bookmark-current-buffer) + (bookmark-buffer-name)))) + (insert str))) + + +(defun bookmark-buffer-name () + "Return the name of the current buffer's file, non-directory. +In Info, return the current node." + (cond + ;; Are we in Info? + ((string-equal mode-name "Info") Info-current-node) + ;; Or are we a file? + (buffer-file-name (file-name-nondirectory buffer-file-name)) + ;; Or are we a directory? + ((and (boundp 'dired-directory) dired-directory) + (let* ((dirname (if (stringp dired-directory) + dired-directory + (car dired-directory))) + (idx (1- (length dirname)))) + ;; Strip the trailing slash. + (if (= ?/ (aref dirname idx)) + (file-name-nondirectory (substring dirname 0 idx)) + ;; Else return the current-buffer + (buffer-name (current-buffer))))) + ;; If all else fails, use the buffer's name. + (t + (buffer-name (current-buffer))))) + (defun bookmark-yank-word () (interactive) @@ -310,69 +1002,45 @@ the list of bookmarks.\)" (let ((string (save-excursion (set-buffer bookmark-current-buffer) (goto-char bookmark-yank-point) - (buffer-substring + (buffer-substring-no-properties (point) - (save-excursion + (progn (forward-word 1) (setq bookmark-yank-point (point))))))) (insert string))) -(defun bookmark-make (parg str) - (if (and (assoc str bookmark-alist) (not parg)) - ;; already existing boookmark under that name and - ;; no prefix arg means just overwrite old bookmark - (setcdr (assoc str bookmark-alist) - (list (bookmark-make-cell))) - - ;; otherwise just cons it onto the front (either the bookmark - ;; doesn't exist already, or there is no prefix arg. In either - ;; case, we want the new bookmark consed onto the alist...) - - (setq bookmark-alist - (cons - (list str - (bookmark-make-cell)) - bookmark-alist))) - ;; Added by db - (setq bookmark-current-bookmark str) - (setq bookmark-alist-modification-count - (1+ bookmark-alist-modification-count)) - (if (bookmark-time-to-save-p) - (bookmark-save))) - -(defun bookmark-make-cell () - ;; make the cell that is the cdr of a bookmark alist element. It - ;; looks like this: - ;; (filename search-forward-str search-back-str point) - (list - (bookmark-buffer-file-name) - (if (>= (- (point-max) (point)) bookmark-search-size) - (buffer-substring - (point) - (+ (point) bookmark-search-size)) - nil) - (if (>= (- (point) (point-min)) bookmark-search-size) - (buffer-substring - (point) - (- (point) bookmark-search-size)) - nil) - (point))) (defun bookmark-buffer-file-name () - (or - buffer-file-name - (if (and (boundp 'dired-directory) dired-directory) - (if (stringp dired-directory) - dired-directory - (car dired-directory))))) - -(defun bookmark-try-default-file () + "Return the current buffer's file in a way useful for bookmarks. +For example, if this is a Info buffer, return the Info file's name." + (if (eq major-mode 'Info-mode) + Info-current-file + (or + buffer-file-name + (if (and (boundp 'dired-directory) dired-directory) + (if (stringp dired-directory) + dired-directory + (car dired-directory)))))) + + +(defun bookmark-maybe-load-default-file () (and (not bookmarks-already-loaded) (null bookmark-alist) - (file-readable-p (expand-file-name bookmark-file)) - (progn - (bookmark-load bookmark-file t t) - (setq bookmarks-already-loaded t)))) + (prog2 + (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))) + ;; 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))) + (defun bookmark-maybe-sort-alist () ;;Return the bookmark-alist for display. If the bookmark-sort-flag @@ -383,72 +1051,71 @@ the list of bookmarks.\)" (function (lambda (x y) (string-lessp (car x) (car y)))))))) + ;;;###autoload -(defun bookmark-jump (str) +(defun bookmark-jump (bookmark) "Jump to bookmark BOOKMARK (a point in some file). You may have a problem using this function if the value of variable `bookmark-alist' is nil. If that happens, you need to load in some bookmarks. See help on function `bookmark-load' for more about this. -If the file pointed to by BOOKMARK no longer exists, `bookmark-jump' -asks you to specify a different file to use instead. If you specify -one, it also updates BOOKMARK to refer to that file." - (interactive (progn (bookmark-try-default-file) - (let* ((completion-ignore-case - bookmark-completion-ignore-case) - (default - (or (and - (assoc bookmark-current-bookmark - bookmark-alist) - bookmark-current-bookmark) - (and (assoc (buffer-name (current-buffer)) - bookmark-alist) - (buffer-name (current-buffer))))) - (str - (completing-read - (if default - (format "Jump to bookmark (%s): " - default) - "Jump to bookmark: ") - bookmark-alist - nil - 0))) - (and (string-equal "" str) - (setq str default)) - (list str)))) - (let ((cell (bookmark-jump-noselect str))) +If the file pointed to by BOOKMARK no longer exists, you will be asked +if you wish to give the bookmark a new location, and bookmark-jump +will then jump to the new location, as well as recording it in place +of the old one in the permanent bookmark record." + (interactive + (bookmark-completing-read "Jump to bookmark" bookmark-current-bookmark)) + (bookmark-maybe-historicize-string bookmark) + (let ((cell (bookmark-jump-noselect bookmark))) (and cell (switch-to-buffer (car cell)) - (goto-char (cdr cell))))) + (goto-char (cdr cell)) + (if bookmark-automatically-show-annotations + ;; if there is an annotation for this bookmark, + ;; show it in a buffer. + (bookmark-show-annotation bookmark))))) + (defun bookmark-jump-noselect (str) ;; a leetle helper for bookmark-jump :-) ;; returns (BUFFER . POINT) - (let ((whereto-list (car (cdr (assoc str bookmark-alist))))) - (let* ((file (expand-file-name (car whereto-list))) - (orig-file file) - (forward-str (car (cdr whereto-list))) - (behind-str (car (cdr (cdr whereto-list)))) - (place (car (cdr (cdr (cdr whereto-list)))))) - (if (or - (file-exists-p file) - ;; else try some common compression extensions - ;; and Emacs better handle it right! - (setq file - (or - (let ((altname (concat file ".Z"))) - (and (file-exists-p altname) - altname)) - (let ((altname (concat file ".gz"))) - (and (file-exists-p altname) - altname)) - (let ((altname (concat file ".z"))) - (and (file-exists-p altname) - altname))))) - (save-excursion - (set-buffer (find-file-noselect file)) - (goto-char place) + (bookmark-maybe-load-default-file) + (let* ((file (expand-file-name (bookmark-get-filename str))) + (forward-str (bookmark-get-front-context-string str)) + (behind-str (bookmark-get-rear-context-string str)) + (place (bookmark-get-position str)) + (info-node (bookmark-get-info-node str)) + (orig-file file) + ) + (if (or + (file-exists-p file) + ;; Else try some common compression extensions, which Emacs + ;; usually handles right. I hope. + (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)) + ;; Check VC incarnations, preparatory to checkout + (if (vc-backend file) file nil)))) + (save-excursion + (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 @@ -456,166 +1123,161 @@ one, it also updates BOOKMARK to refer to that file." ;; rather than after and remain perhaps unaware of the changes. (if forward-str (if (search-forward forward-str (point-max) t) - (backward-char bookmark-search-size))) + (goto-char (match-beginning 0)))) (if behind-str (if (search-backward behind-str (point-min) t) - (forward-char bookmark-search-size))) + (goto-char (match-end 0)))) ;; added by db (setq bookmark-current-bookmark str) - (cons (current-buffer) (point))) - (progn - (ding) - (if (y-or-n-p (concat (file-name-nondirectory orig-file) - " nonexistent. Relocate \"" - str - "\"? ")) - (progn - (bookmark-relocate str) - ;; gasp! It's a recursive function call in Emacs Lisp! - (bookmark-jump-noselect str)) - (message - "Bookmark not relocated, but deleting it would be a good idea.") - nil)))))) + (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) + (if (y-or-n-p (concat (file-name-nondirectory orig-file) + " nonexistent. Relocate \"" + str + "\"? ")) + (progn + (bookmark-relocate str) + ;; gasp! It's a recursive function call in Emacs Lisp! + (bookmark-jump-noselect str)) + (message + "Bookmark not relocated; consider removing it \(%s\)." str) + nil)))) + ;;;###autoload (defun bookmark-relocate (bookmark) - "Relocate bookmark BOOKMARK. -Prompt for a filename, and makes the bookmark 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 (let ((completion-ignore-case - bookmark-completion-ignore-case)) - (progn (bookmark-try-default-file) - (list (completing-read - "Bookmark to relocate: " - bookmark-alist - nil - 0))))) - (let* ((bmrk (assoc bookmark bookmark-alist)) - (bmrk-filename (car (car (cdr bmrk)))) + "Relocate BOOKMARK 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 (bookmark-completing-read "Bookmark to relocate")) + (bookmark-maybe-historicize-string bookmark) + (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))))) - (setcar (car (cdr bmrk)) newloc))) + (read-file-name + (format "Relocate %s to: " bookmark) + (file-name-directory bmrk-filename))))) + (bookmark-set-filename bookmark newloc) + (bookmark-bmenu-surreptitiously-rebuild-list))) + ;;;###autoload -(defun bookmark-locate (str &optional no-insertion) +(defun bookmark-insert-location (bookmark &optional no-history) "Insert the name of the file associated with BOOKMARK. -Optional second arg NO-INSERTION means merely return the filename as a -string." - (interactive (let ((completion-ignore-case - bookmark-completion-ignore-case)) - (progn (bookmark-try-default-file) - (list (completing-read - "Insert bookmark location: " - bookmark-alist - nil - 0))))) - (let ((where (car (car (cdr (assoc str bookmark-alist)))))) - (if no-insertion - where - (insert where)))) +Optional second arg NO-HISTORY means don't record this in the +minibuffer history list `bookmark-history'." + (interactive (bookmark-completing-read "Insert bookmark location")) + (or no-history (bookmark-maybe-historicize-string bookmark)) + (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))))) + +;;;###autoload +(defalias 'bookmark-locate 'bookmark-insert-location) + +(defun bookmark-location (bookmark) + "Return the name of the file associated with BOOKMARK." + (bookmark-maybe-load-default-file) + (bookmark-get-filename bookmark)) + ;;;###autoload (defun bookmark-rename (old &optional new) - "Change the name of OLD-BOOKMARK to NEWNAME. -If called from keyboard, prompts for OLD-BOOKMARK and NEWNAME. -If called from menubar, OLD-BOOKMARK is selected from a menu, and -prompts for NEWNAME. -If called from Lisp, prompts for NEWNAME if only OLD-BOOKMARK was -passed as an argument. If called with two strings, then no prompting -is done. You must pass at least OLD-BOOKMARK when calling from Lisp. + "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. + +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. While you are entering the new name, consecutive C-w's insert -consectutive words from the text of the buffer into the new bookmark -name, and C-v inserts the name of the file." - (interactive (let ((completion-ignore-case - bookmark-completion-ignore-case)) - (progn (bookmark-try-default-file) - (list (completing-read "Old bookmark name: " - bookmark-alist - nil - 0))))) - (progn - (setq bookmark-current-point (point)) - (setq bookmark-yank-point (point)) - (setq bookmark-current-buffer (current-buffer)) - (let ((cell (assoc old bookmark-alist)) - (str - (or new ; use second arg, if non-nil - (read-from-minibuffer - "New name: " - nil - (let ((now-map (copy-keymap minibuffer-local-map))) - (progn (define-key now-map "\C-w" - 'bookmark-yank-word) - (define-key now-map "\C-v" - 'bookmark-insert-current-file-name)) - now-map))))) - (progn - (setcar cell str) - (setq bookmark-current-bookmark str) - (if (get-buffer "*Bookmark List*") - (save-excursion (save-window-excursion (list-bookmarks)))) - (setq bookmark-alist-modification-count - (1+ bookmark-alist-modification-count)) - (if (bookmark-time-to-save-p) - (bookmark-save)))))) +consecutive words from the text of the buffer into the new bookmark +name." + (interactive (bookmark-completing-read "Old bookmark name")) + (bookmark-maybe-historicize-string old) + (bookmark-maybe-load-default-file) + + (setq bookmark-current-point (point)) + (setq bookmark-yank-point (point)) + (setq bookmark-current-buffer (current-buffer)) + (let ((newname + (or new ; 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) + now-map) + nil + 'bookmark-history)))) + (bookmark-set-name old newname) + (setq bookmark-current-bookmark newname) + (bookmark-bmenu-surreptitiously-rebuild-list) + (setq bookmark-alist-modification-count + (1+ bookmark-alist-modification-count)) + (if (bookmark-time-to-save-p) + (bookmark-save)))) + ;;;###autoload -(defun bookmark-insert (str) +(defun bookmark-insert (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 this." - (interactive (let ((completion-ignore-case - bookmark-completion-ignore-case)) - (progn (bookmark-try-default-file) - (list (completing-read - "Insert bookmark contents: " - bookmark-alist - nil - 0))))) + (interactive (bookmark-completing-read "Insert bookmark contents")) + (bookmark-maybe-historicize-string bookmark) + (bookmark-maybe-load-default-file) (let ((orig-point (point)) (str-to-insert (save-excursion - (set-buffer (car (bookmark-jump-noselect str))) - (buffer-substring (point-min) (point-max))))) + (set-buffer (car (bookmark-jump-noselect bookmark))) + (buffer-string)))) (insert str-to-insert) (push-mark) (goto-char orig-point))) + ;;;###autoload -(defun bookmark-delete (str) - "Delete the bookmark named NAME from the bookmark list. +(defun bookmark-delete (bookmark &optional batch) + "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 -one most recently used in this file, if any\)." - (interactive (let ((completion-ignore-case - bookmark-completion-ignore-case)) - (progn (bookmark-try-default-file) - (list - (completing-read - "Delete bookmark: " - bookmark-alist - nil - 0 - bookmark-current-bookmark))))) - (let ((will-go (assoc str bookmark-alist))) +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 + (bookmark-completing-read "Delete bookmark" bookmark-current-bookmark)) + (bookmark-maybe-historicize-string bookmark) + (bookmark-maybe-load-default-file) + (let ((will-go (bookmark-get-bookmark bookmark))) (setq bookmark-alist (delq will-go bookmark-alist)) ;; Added by db, nil bookmark-current-bookmark if the last - ;; occurence has been deleted - (or (assoc bookmark-current-bookmark bookmark-alist) + ;; occurrence has been deleted + (or (bookmark-get-bookmark bookmark-current-bookmark) (setq bookmark-current-bookmark nil))) - (if (get-buffer "*Bookmark List*") - (save-excursion (save-window-excursion (list-bookmarks)))) - (setq bookmark-alist-modification-count - (1+ bookmark-alist-modification-count)) - (if (bookmark-time-to-save-p) - (bookmark-save))) + ;; Don't rebuild the list + (if batch + nil + (bookmark-bmenu-surreptitiously-rebuild-list) + (setq bookmark-alist-modification-count + (1+ bookmark-alist-modification-count)) + (if (bookmark-time-to-save-p) + (bookmark-save)))) + (defun bookmark-time-to-save-p (&optional last-time) ;; By Gregory M. Saunders @@ -632,19 +1294,22 @@ one most recently used in this file, if any\)." (t nil))) + ;;;###autoload (defun bookmark-write () - "Write bookmarks to a specified file. + "Write bookmarks to a file (reading the file name with the minibuffer). Don't use this in Lisp programs; use `bookmark-save' instead." (interactive) - (bookmark-try-default-file) + (bookmark-maybe-load-default-file) (bookmark-save t)) + ;;;###autoload (defun bookmark-save (&optional parg file) "Save currently defined bookmarks. Saves by default in the file defined by the variable -`bookmark-file'. With a prefix arg, save it in file FILE. +`bookmark-default-file'. With a prefix arg, save it in file FILE +\(second argument\). If you are calling this from Lisp, the two arguments are PREFIX-ARG and FILE, and if you just want it to write to the default file, then @@ -655,13 +1320,13 @@ 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 for a file, defaulting to the file defined by variable -`bookmark-file'." +`bookmark-default-file'." (interactive "P") - (bookmark-try-default-file) + (bookmark-maybe-load-default-file) (cond ((and (null parg) (null file)) ;;whether interactive or not, write to default file - (bookmark-write-file bookmark-file)) + (bookmark-write-file bookmark-default-file)) ((and (null parg) file) ;;whether interactive or not, write to given file (bookmark-write-file file)) @@ -676,16 +1341,19 @@ for a file, defaulting to the file defined by variable ;; set, which is what we want. (setq bookmark-alist-modification-count 0)) + + (defun bookmark-write-file (file) (save-excursion (save-window-excursion (if (>= baud-rate 9600) - (message (format "Saving bookmarks to file %s." file))) + (message "Saving bookmarks to file %s..." file)) (set-buffer (let ((enable-local-variables nil)) (find-file-noselect file))) (goto-char (point-min)) (delete-region (point-min) (point-max)) - (print bookmark-alist (current-buffer)) + (bookmark-insert-file-format-version-stamp) + (pp bookmark-alist (current-buffer)) (let ((version-control (cond ((null bookmark-version-control) nil) @@ -694,323 +1362,466 @@ for a file, defaulting to the file defined by variable (t t)))) (write-file file) - (kill-buffer (current-buffer)))))) + (kill-buffer (current-buffer)) + (if (>= baud-rate 9600) + (message "Saving bookmarks to file %s...done" file)) + )))) + + +(defun bookmark-import-new-list (new-list) + ;; Walk over the new list, adding each individual bookmark + ;; carefully. "Carefully" means checking against the existing + ;; bookmark-alist and renaming the new bookmarks with extensions + ;; as necessary. + (let ((lst new-list) + (names (bookmark-all-names))) + (while lst + (let* ((full-record (car lst))) + (bookmark-maybe-rename full-record names) + (setq bookmark-alist (nconc bookmark-alist (list full-record))) + (setq names (cons (bookmark-name-from-full-record full-record) names)) + (setq lst (cdr lst)))))) + + +(defun bookmark-maybe-rename (full-record names) + ;; just a helper for bookmark-import-new-list; it is only for + ;; readability that this is not inlined. + ;; + ;; Once this has found a free name, it sets full-record to that + ;; name. + (let ((found-name (bookmark-name-from-full-record full-record))) + (if (member found-name names) + ;; We've got a conflict, so generate a new name + (let ((count 2) + (new-name found-name)) + (while (member new-name names) + (setq new-name (concat found-name (format "<%d>" count))) + (setq count (1+ count))) + (bookmark-set-name full-record new-name))))) + ;;;###autoload -(defun bookmark-load (file &optional revert no-msg) +(defun bookmark-load (file &optional overwrite no-msg) "Load bookmarks from FILE (which must be in bookmark format). Appends loaded bookmarks to the front of the list of bookmarks. If -optional second argument REVERT is non-nil, existing bookmarks are +optional second argument OVERWRITE is non-nil, existing bookmarks are destroyed. Optional third arg NO-MSG means don't display any messages while loading. If you load a file that doesn't contain a proper bookmark alist, you will corrupt Emacs's bookmark list. Generally, you should only load in files that were created with the bookmark functions in the first -place. Your own personal bookmark file, `~/.emacs-bkmrks', is +place. Your own personal bookmark file, `~/.emacs.bmk', is maintained automatically by Emacs; you shouldn't need to load it -explicitly." +explicitly. + +If you load a file containing bookmarks with the same names as +bookmarks already present in your Emacs, the new bookmarks will get +unique numeric suffixes \"<2>\", \"<3>\", ... following the same +method buffers use to resolve name collisions." (interactive - (progn (bookmark-try-default-file) - (list (read-file-name - (format "Load bookmarks from: (%s) " - bookmark-file) - ;;Default might not be used often, - ;;but there's no better default, and - ;;I guess it's better than none at all. - "~/" bookmark-file 'confirm)))) + (list (read-file-name + (format "Load bookmarks from: (%s) " + 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. + "~/" bookmark-default-file 'confirm))) (setq file (expand-file-name file)) (if (file-readable-p file) (save-excursion (save-window-excursion (if (and (null no-msg) (>= baud-rate 9600)) - (message (format "Loading bookmarks from %s..." file))) + (message "Loading bookmarks from %s..." file)) (set-buffer (let ((enable-local-variables nil)) (find-file-noselect file))) (goto-char (point-min)) - (let ((blist (car (read-from-string - (buffer-substring (point-min) (point-max)))))) + (bookmark-maybe-upgrade-file-format) + (let ((blist (bookmark-alist-from-buffer))) (if (listp blist) (progn - (if (not revert) - (setq bookmark-alist-modification-count - (1+ bookmark-alist-modification-count)) - (setq bookmark-alist-modification-count 0)) - (setq bookmark-alist - (append blist (if (not revert) bookmark-alist))) - (if (get-buffer "*Bookmark List*") - (save-excursion (list-bookmarks)))) - (error (format "Invalid bookmark list in %s." file)))) + (if overwrite + (progn + (setq bookmark-alist blist) + (setq bookmark-alist-modification-count 0)) + ;; else + (bookmark-import-new-list blist) + (setq bookmark-alist-modification-count + (1+ bookmark-alist-modification-count))) + (if (string-equal + (expand-file-name bookmark-default-file) + file) + (setq bookmarks-already-loaded t)) + (bookmark-bmenu-surreptitiously-rebuild-list)) + (error "Invalid bookmark list in %s" file))) (kill-buffer (current-buffer))) (if (and (null no-msg) (>= baud-rate 9600)) - (message (format "Loading bookmarks from %s... done" file)))) - (error (format "Cannot read bookmark file %s." file)))) + (message "Loading bookmarks from %s...done" file))) + (error "Cannot read bookmark file %s" file))) -;;;; bookmark-menu-mode stuff ;;;; -(defvar Bookmark-menu-bookmark-column nil) + +;;; Code supporting the dired-like bookmark menu. Prefix is +;;; "bookmark-bmenu" for "buffer-menu": -(defvar Bookmark-menu-hidden-bookmarks ()) -(defvar Bookmark-menu-file-column 30 - "*Column at which to display filenames in a buffer listing bookmarks. -You can toggle whether files are shown with \\\\[Bookmark-menu-toggle-filenames].") +(defvar bookmark-bmenu-bookmark-column nil) + + +(defvar bookmark-bmenu-hidden-bookmarks ()) -(defvar Bookmark-menu-toggle-filenames t - "*Non-nil means show filenames when listing bookmarks. -This may result in truncated bookmark names. To disable this, put the -following in your .emacs: -\(setq Bookmark-menu-toggle-filenames nil\)") +(defvar bookmark-bmenu-mode-map nil) -(defvar Bookmark-menu-mode-map nil) -(if Bookmark-menu-mode-map +(if bookmark-bmenu-mode-map nil - (setq Bookmark-menu-mode-map (make-keymap)) - (suppress-keymap Bookmark-menu-mode-map t) - (define-key Bookmark-menu-mode-map "q" 'Bookmark-menu-quit) - (define-key Bookmark-menu-mode-map "v" 'Bookmark-menu-select) - (define-key Bookmark-menu-mode-map "w" 'Bookmark-menu-locate) - (define-key Bookmark-menu-mode-map "2" 'Bookmark-menu-2-window) - (define-key Bookmark-menu-mode-map "1" 'Bookmark-menu-1-window) - (define-key Bookmark-menu-mode-map "j" 'Bookmark-menu-this-window) - (define-key Bookmark-menu-mode-map "f" 'Bookmark-menu-this-window) - (define-key Bookmark-menu-mode-map "o" 'Bookmark-menu-other-window) - (define-key Bookmark-menu-mode-map "\C-o" 'Bookmark-menu-switch-other-window) - (define-key Bookmark-menu-mode-map "s" 'Bookmark-menu-save) - (define-key Bookmark-menu-mode-map "k" 'Bookmark-menu-delete) - (define-key Bookmark-menu-mode-map "\C-d" 'Bookmark-menu-delete-backwards) - (define-key Bookmark-menu-mode-map "x" 'Bookmark-menu-execute) - (define-key Bookmark-menu-mode-map "\C-k" 'Bookmark-menu-delete) - (define-key Bookmark-menu-mode-map "d" 'Bookmark-menu-delete) - (define-key Bookmark-menu-mode-map " " 'next-line) - (define-key Bookmark-menu-mode-map "n" 'next-line) - (define-key Bookmark-menu-mode-map "p" 'previous-line) - (define-key Bookmark-menu-mode-map "\177" 'Bookmark-menu-backup-unmark) - (define-key Bookmark-menu-mode-map "?" 'describe-mode) - (define-key Bookmark-menu-mode-map "u" 'Bookmark-menu-unmark) - (define-key Bookmark-menu-mode-map "m" 'Bookmark-menu-mark) - (define-key Bookmark-menu-mode-map "l" 'Bookmark-menu-load) - (define-key Bookmark-menu-mode-map "r" 'Bookmark-menu-rename) - (define-key Bookmark-menu-mode-map "t" 'Bookmark-menu-toggle-filenames)) - -;; Bookmark Menu mode is suitable only for specially formatted data. -(put 'Bookmark-menu-mode 'mode-class 'special) - -;; need to display whether or not bookmark exists as a buffer in flag -;; column. + (setq bookmark-bmenu-mode-map (make-keymap)) + (suppress-keymap bookmark-bmenu-mode-map t) + (define-key bookmark-bmenu-mode-map "q" 'quit-window) + (define-key bookmark-bmenu-mode-map "v" 'bookmark-bmenu-select) + (define-key bookmark-bmenu-mode-map "w" 'bookmark-bmenu-locate) + (define-key bookmark-bmenu-mode-map "2" 'bookmark-bmenu-2-window) + (define-key bookmark-bmenu-mode-map "1" 'bookmark-bmenu-1-window) + (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 "o" 'bookmark-bmenu-other-window) + (define-key bookmark-bmenu-mode-map "\C-o" + 'bookmark-bmenu-switch-other-window) + (define-key bookmark-bmenu-mode-map "s" 'bookmark-bmenu-save) + (define-key bookmark-bmenu-mode-map "k" 'bookmark-bmenu-delete) + (define-key bookmark-bmenu-mode-map "\C-d" 'bookmark-bmenu-delete-backwards) + (define-key bookmark-bmenu-mode-map "x" 'bookmark-bmenu-execute-deletions) + (define-key bookmark-bmenu-mode-map "d" 'bookmark-bmenu-delete) + (define-key bookmark-bmenu-mode-map " " 'next-line) + (define-key bookmark-bmenu-mode-map "n" 'next-line) + (define-key bookmark-bmenu-mode-map "p" 'previous-line) + (define-key bookmark-bmenu-mode-map "\177" 'bookmark-bmenu-backup-unmark) + (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 "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 "A" 'bookmark-bmenu-show-all-annotations) + (define-key bookmark-bmenu-mode-map "e" 'bookmark-bmenu-edit-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. +(put 'bookmark-bmenu-mode 'mode-class 'special) + + +;; todo: need to display whether or not bookmark exists as a buffer in +;; flag column. ;; Format: -;; FLAGS BOOKMARK (/FILE/NAME/HERE/WHAT/REGEXP/TO/USE?) -;; goto bookmark-column and then search till "(/[^)]*)$" or "(/.*)$" ? +;; FLAGS BOOKMARK [ LOCATION ] + + +(defun bookmark-bmenu-surreptitiously-rebuild-list () + "Rebuild the Bookmark List if it exists. +Don't affect the buffer ring order." + (if (get-buffer "*Bookmark List*") + (save-excursion + (save-window-excursion + (bookmark-bmenu-list))))) -;;;###autoload -(defalias 'edit-bookmarks 'list-bookmarks) ;;;###autoload -(defun list-bookmarks () +(defun bookmark-bmenu-list () "Display a list of existing bookmarks. The list is displayed in a buffer named `*Bookmark List*'. -The leftmost column displays a `D' if the bookmark is flagged for -deletion, or `>' if it is flagged for displaying." +The leftmost column displays a D if the bookmark is flagged for +deletion, or > if it is flagged for displaying." (interactive) - (bookmark-try-default-file) - (switch-to-buffer (get-buffer-create "*Bookmark List*")) + (bookmark-maybe-load-default-file) + (if (interactive-p) + (switch-to-buffer (get-buffer-create "*Bookmark List*")) + (set-buffer (get-buffer-create "*Bookmark List*"))) (let ((buffer-read-only nil)) (delete-region (point-max) (point-min)) (goto-char (point-min)) ;sure are playing it safe... (insert "% Bookmark\n- --------\n") (bookmark-maybe-sort-alist) - (let ((lst bookmark-alist)) - (while lst - (insert - (concat " " (car (car lst)) "\n")) - (setq lst (cdr lst))))) + (mapcar + (lambda (full-record) + ;; if a bookmark has an annotation, prepend a "*" + ;; in the list of bookmarks. + (let ((annotation (bookmark-get-annotation + (bookmark-name-from-full-record full-record)))) + (if (and annotation (not (string-equal annotation ""))) + (insert " *") + (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)) + (insert "\n") + ))) + bookmark-alist)) (goto-char (point-min)) (forward-line 2) - (bookmark-menu-mode) - (if Bookmark-menu-toggle-filenames - (Bookmark-menu-toggle-filenames t))) + (bookmark-bmenu-mode) + (if bookmark-bmenu-toggle-filenames + (bookmark-bmenu-toggle-filenames t))) + +;;;###autoload +(defalias 'list-bookmarks 'bookmark-bmenu-list) +;;;###autoload +(defalias 'edit-bookmarks 'bookmark-bmenu-list) + + -(defun bookmark-menu-mode () +(defun bookmark-bmenu-mode () "Major mode for editing a list of bookmarks. Each line describes one of the bookmarks in Emacs. Letters do not insert themselves; instead, they are commands. -\\ -\\[Bookmark-menu-mark] -- mark bookmark to be displayed. -\\[Bookmark-menu-select] -- select bookmark of line point is on. - Also show bookmarks marked using `m' in other windows. -\\[Bookmark-menu-toggle-filenames] -- toggle displaying of filenames (they may obscure long bookmark names). -\\[Bookmark-menu-locate] -- display (in minibuffer) location of this bookmark. -\\[Bookmark-menu-1-window] -- select this bookmark in full-frame window. -\\[Bookmark-menu-2-window] -- select this bookmark in one window, +Bookmark names preceded by a \"*\" have annotations. +\\ +\\[bookmark-bmenu-mark] -- mark bookmark to be displayed. +\\[bookmark-bmenu-select] -- select bookmark of line point is on. + Also show bookmarks marked using m in other windows. +\\[bookmark-bmenu-toggle-filenames] -- toggle displaying of filenames (they may obscure long bookmark names). +\\[bookmark-bmenu-locate] -- display (in minibuffer) location of this bookmark. +\\[bookmark-bmenu-1-window] -- select this bookmark in full-frame window. +\\[bookmark-bmenu-2-window] -- select this bookmark in one window, together with bookmark selected before this one in another window. -\\[Bookmark-menu-this-window] -- select this bookmark in place of the bookmark menu buffer. -\\[Bookmark-menu-other-window] -- select this bookmark in another window, +\\[bookmark-bmenu-this-window] -- select this bookmark in place of the bookmark menu buffer. +\\[bookmark-bmenu-other-window] -- select this bookmark in another window, so the bookmark menu bookmark remains visible in its window. -\\[Bookmark-menu-switch-other-window] -- switch the other window to this bookmark. -\\[Bookmark-menu-rename] -- rename this bookmark \(prompts for new name\). -\\[Bookmark-menu-delete] -- mark this bookmark to be deleted, and move down. -\\[Bookmark-menu-delete-backwards] -- mark this bookmark to be deleted, and move up. -\\[Bookmark-menu-execute] -- delete marked bookmarks. -\\[Bookmark-menu-save] -- save the current bookmark list in the default file. +\\[bookmark-bmenu-switch-other-window] -- switch the other window to this bookmark. +\\[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-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. -\\[Bookmark-menu-load] -- load in a file of bookmarks (prompts for file.) -\\[Bookmark-menu-unmark] -- remove all kinds of marks from current line. +\\[bookmark-bmenu-load] -- load in a file of bookmarks (prompts for file.) +\\[bookmark-bmenu-unmark] -- remove all kinds of marks from current line. With prefix argument, also move up one line. -\\[Bookmark-menu-backup-unmark] -- back up a line and remove marks." +\\[bookmark-bmenu-backup-unmark] -- back up a line and remove marks. +\\[bookmark-bmenu-show-annotation] -- show the annotation, if it exists, for the current bookmark + 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-menu-mode-map) + (use-local-map bookmark-bmenu-mode-map) (setq truncate-lines t) (setq buffer-read-only t) - (setq major-mode 'bookmark-menu-mode) + (setq major-mode 'bookmark-bmenu-mode) (setq mode-name "Bookmark Menu") - (run-hooks 'bookmark-menu-mode-hook)) + (run-hooks 'bookmark-bmenu-mode-hook)) -(defun Bookmark-menu-toggle-filenames (&optional parg) + +(defun bookmark-bmenu-toggle-filenames (&optional show) "Toggle whether filenames are shown in the bookmark list. Optional argument SHOW means show them unconditionally." (interactive) (cond - (parg - (setq Bookmark-menu-toggle-filenames nil) - (Bookmark-menu-show-filenames) - (setq Bookmark-menu-toggle-filenames t)) - (Bookmark-menu-toggle-filenames - (Bookmark-menu-hide-filenames) - (setq Bookmark-menu-toggle-filenames nil)) + (show + (setq bookmark-bmenu-toggle-filenames nil) + (bookmark-bmenu-show-filenames) + (setq bookmark-bmenu-toggle-filenames t)) + (bookmark-bmenu-toggle-filenames + (bookmark-bmenu-hide-filenames) + (setq bookmark-bmenu-toggle-filenames nil)) (t - (Bookmark-menu-show-filenames) - (setq Bookmark-menu-toggle-filenames t)))) + (bookmark-bmenu-show-filenames) + (setq bookmark-bmenu-toggle-filenames t)))) + -(defun Bookmark-menu-show-filenames (&optional force) - (if (and (not force) Bookmark-menu-toggle-filenames) +(defun bookmark-bmenu-show-filenames (&optional force) + (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-menu-hidden-bookmarks ()) + (setq bookmark-bmenu-hidden-bookmarks ()) (let ((buffer-read-only nil)) (while (< (point) (point-max)) - (let ((bmrk (Bookmark-menu-bookmark))) - (setq Bookmark-menu-hidden-bookmarks - (cons bmrk Bookmark-menu-hidden-bookmarks)) - (move-to-column Bookmark-menu-file-column t) - (delete-region (point) (progn (end-of-line) (point))) + (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 window-system + (remove-text-properties start (point) + '(mouse-face)))) + (delete-region (point) (progn (end-of-line) (point))) (insert " ") - (bookmark-locate bmrk) + ;; Pass the NO-HISTORY arg: + (bookmark-insert-location bmrk t) (forward-line 1)))))))) -(defun Bookmark-menu-hide-filenames (&optional force) - (if (and (not force) Bookmark-menu-toggle-filenames) + +(defun bookmark-bmenu-hide-filenames (&optional force) + (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-menu-hidden-bookmarks - (nreverse Bookmark-menu-hidden-bookmarks)) + (setq bookmark-bmenu-hidden-bookmarks + (nreverse bookmark-bmenu-hidden-bookmarks)) (save-excursion (goto-char (point-min)) (search-forward "Bookmark") (backward-word 1) - (setq Bookmark-menu-bookmark-column (current-column))) + (setq bookmark-bmenu-bookmark-column (current-column))) (save-excursion (let ((buffer-read-only nil)) - (while Bookmark-menu-hidden-bookmarks - (move-to-column Bookmark-menu-bookmark-column t) - (kill-line) - (insert (car Bookmark-menu-hidden-bookmarks)) - (setq Bookmark-menu-hidden-bookmarks - (cdr Bookmark-menu-hidden-bookmarks)) + (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 window-system + (put-text-property start + (save-excursion (re-search-backward + "[^ \t]") + (1+ (point))) + 'mouse-face 'highlight))) + (setq bookmark-bmenu-hidden-bookmarks + (cdr bookmark-bmenu-hidden-bookmarks)) (forward-line 1)))))))) -;; if you look at this next function from far away, it resembles a -;; gun. But only with this comment above... -(defun Bookmark-menu-check-position () - ;; Returns t if on a line with a bookmark. - ;; Otherwise, repositions and returns t. - ;; written by David Hughes - ;; Mucho thanks, David! -karl + +(defun bookmark-bmenu-check-position () + ;; Returns non-nil if on a line with a bookmark. + ;; (The actual value returned is bookmark-alist). + ;; Else reposition and try again, else return nil. (cond ((< (count-lines (point-min) (point)) 2) (goto-char (point-min)) (forward-line 2) - t) + bookmark-alist) ((and (bolp) (eobp)) (beginning-of-line 0) - t) + bookmark-alist) (t - t))) + bookmark-alist))) + -(defun Bookmark-menu-bookmark () +(defun bookmark-bmenu-bookmark () ;; return a string which is bookmark of this line. - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (save-excursion (save-window-excursion (goto-char (point-min)) (search-forward "Bookmark") (backward-word 1) - (setq Bookmark-menu-bookmark-column (current-column))))) - (if Bookmark-menu-toggle-filenames - (Bookmark-menu-hide-filenames)) + (setq bookmark-bmenu-bookmark-column (current-column))))) + (if bookmark-bmenu-toggle-filenames + (bookmark-bmenu-hide-filenames)) (save-excursion (save-window-excursion (beginning-of-line) - (forward-char Bookmark-menu-bookmark-column) + (forward-char bookmark-bmenu-bookmark-column) (prog1 - (buffer-substring (point) + (buffer-substring-no-properties (point) (progn (end-of-line) (point))) ;; well, this is certainly crystal-clear: - (if Bookmark-menu-toggle-filenames - (Bookmark-menu-toggle-filenames t)))))) + (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, +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)))))) + + +(defun bookmark-show-all-annotations () + "Display the annotations for all bookmarks in a buffer." + (let ((old-buf (current-buffer))) + (pop-to-buffer (get-buffer-create "*Bookmark Annotation*") t) + (delete-region (point-min) (point-max)) + (mapcar + (lambda (full-record) + (let* ((name (bookmark-name-from-full-record full-record)) + (ann (bookmark-get-annotation name))) + (insert (concat name ":\n")) + (if (and ann (not (string-equal ann ""))) + ;; insert the annotation, indented by 4 spaces. + (progn + (save-excursion (insert ann)) + (while (< (point) (point-max)) + (beginning-of-line) ; paranoia + (insert " ") + (forward-line) + (end-of-line)))))) + bookmark-alist) + (goto-char (point-min)) + (pop-to-buffer old-buf))) -(defun Bookmark-menu-mark () - "Mark bookmark on this line to be displayed by \\\\[Bookmark-menu-select] command." + +(defun bookmark-bmenu-mark () + "Mark bookmark on this line to be displayed by \\\\[bookmark-bmenu-select]." (interactive) (beginning-of-line) - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (let ((buffer-read-only nil)) (delete-char 1) (insert ?>) - (forward-line 1)))) + (forward-line 1) + (bookmark-bmenu-check-position)))) + -(defun Bookmark-menu-select () +(defun bookmark-bmenu-select () "Select this line's bookmark; also display bookmarks marked with `>'. -You can mark bookmarks with the \\\\[Bookmark-menu-mark] command." +You can mark bookmarks with the \\\\[bookmark-bmenu-mark] command." (interactive) - (if (Bookmark-menu-check-position) - (let ((bmrk (Bookmark-menu-bookmark)) + (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-menu-bookmark)) + (setq tem (bookmark-bmenu-bookmark)) (let ((buffer-read-only nil)) (delete-char -1) (insert ?\ )) (or (string-equal tem bmrk) - (memq tem others) + (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 (equal (length others) 0) - nil - (while others - (split-window nil tem) - (other-window 1) - (bookmark-jump (car others)) - (setq others (cdr others))) + (if others + (while others + (split-window nil tem) + (other-window 1) + (bookmark-jump (car others)) + (setq others (cdr others))) (other-window 1))))) -(defun Bookmark-menu-save (parg) + +(defun bookmark-bmenu-save (parg) "Save the current list into a bookmark file. With a prefix arg, prompts for a file to save them in." (interactive "P") @@ -1018,70 +1829,124 @@ With a prefix arg, prompts for a file to save them in." (save-window-excursion (bookmark-save parg)))) -(defun Bookmark-menu-load () - "Load a bookmark file and rebuild list." + +(defun bookmark-bmenu-load () + "Load the bookmark file and rebuild the bookmark menu-buffer." (interactive) - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (save-excursion (save-window-excursion + ;; This will call `bookmark-bmenu-list' (call-interactively 'bookmark-load))))) -(defun Bookmark-menu-1-window () + +(defun bookmark-bmenu-1-window () "Select this line's bookmark, alone, in full frame." (interactive) - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (progn - (bookmark-jump (Bookmark-menu-bookmark)) + (bookmark-jump (bookmark-bmenu-bookmark)) (bury-buffer (other-buffer)) (delete-other-windows)))) -(defun Bookmark-menu-2-window () + +(defun bookmark-bmenu-2-window () "Select this line's bookmark, with previous buffer in second window." (interactive) - (if (Bookmark-menu-check-position) - (let ((bmrk (Bookmark-menu-bookmark)) + (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 ((buff (car (bookmark-jump-noselect bmrk)))) - (pop-to-buffer buff)) + (let* ((pair (bookmark-jump-noselect bmrk)) + (buff (car pair)) + (pos (cdr pair))) + (pop-to-buffer buff) + (goto-char pos)) (bury-buffer menu)))) -(defun Bookmark-menu-this-window () + +(defun bookmark-bmenu-this-window () "Select this line's bookmark in this window." (interactive) - (if (Bookmark-menu-check-position) - (bookmark-jump (Bookmark-menu-bookmark)))) + (if (bookmark-bmenu-check-position) + (bookmark-jump (bookmark-bmenu-bookmark)))) + -(defun Bookmark-menu-other-window () +(defun bookmark-bmenu-other-window () "Select this line's bookmark in other window, leaving bookmark menu visible." (interactive) - (if (Bookmark-menu-check-position) - (let ((buff (car (bookmark-jump-noselect (Bookmark-menu-bookmark))))) - (switch-to-buffer-other-window buff)))) - -(defun Bookmark-menu-switch-other-window () + (let ((bookmark (bookmark-bmenu-bookmark))) + (if (bookmark-bmenu-check-position) + (let* ((pair (bookmark-jump-noselect bookmark)) + (buff (car pair)) + (pos (cdr pair))) + (switch-to-buffer-other-window buff) + (goto-char pos) + (set-window-point (get-buffer-window buff) pos) + (bookmark-show-annotation bookmark))))) + + +(defun bookmark-bmenu-switch-other-window () "Make the other window select this line's bookmark. The current window remains selected." (interactive) - (if (Bookmark-menu-check-position) - (let ((buff (car (bookmark-jump-noselect (Bookmark-menu-bookmark))))) - (display-buffer buff)))) + (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)) + (pos (cdr pair))) + (display-buffer buff) + (let ((o-buffer (current-buffer))) + ;; save-excursion won't do + (set-buffer buff) + (goto-char pos) + (set-window-point (get-buffer-window buff) pos) + (set-buffer o-buffer)) + (bookmark-show-annotation bookmark))))) + +(defun bookmark-bmenu-other-window-with-mouse (event) + "Select bookmark at the mouse pointer in other window, leaving bookmark menu visible." + (interactive "e") + (save-excursion + (set-buffer (window-buffer (posn-window (event-end event)))) + (save-excursion + (goto-char (posn-point (event-end event))) + (bookmark-bmenu-other-window)))) + -(defun Bookmark-menu-quit () - "Quit the bookmark menu." +(defun bookmark-bmenu-show-annotation () + "Show the annotation for the current bookmark in another window." (interactive) - (let ((buffer (current-buffer))) - (switch-to-buffer (other-buffer)) - (bury-buffer buffer))) + (let ((bookmark (bookmark-bmenu-bookmark))) + (if (bookmark-bmenu-check-position) + (bookmark-show-annotation bookmark)))) -(defun Bookmark-menu-unmark (&optional backup) + +(defun bookmark-bmenu-show-all-annotations () + "Show the annotation for all bookmarks in another window." + (interactive) + (bookmark-show-all-annotations)) + + +(defun bookmark-bmenu-edit-annotation () + "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)))) + + +(defun bookmark-bmenu-unmark (&optional backup) "Cancel all requested operations on bookmark on this line and move down. -Optional ARG means move up." +Optional BACKUP means move up." (interactive "P") (beginning-of-line) - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (progn (let ((buffer-read-only nil)) (delete-char 1) @@ -1089,143 +1954,216 @@ Optional ARG means move up." ;; 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))))) + (forward-line (if backup -1 1)) + (bookmark-bmenu-check-position)))) -(defun Bookmark-menu-backup-unmark () + +(defun bookmark-bmenu-backup-unmark () "Move up and cancel all requested operations on bookmark on line above." (interactive) (forward-line -1) - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (progn - (Bookmark-menu-unmark) - (forward-line -1)))) + (bookmark-bmenu-unmark) + (forward-line -1) + (bookmark-bmenu-check-position)))) + -(defun Bookmark-menu-delete () - "Mark bookmark on this line to be deleted by \\\\[Bookmark-menu-execute] command." +(defun bookmark-bmenu-delete () + "Mark bookmark on this line to be deleted. +To carry out the deletions that you've marked, use \\\\[bookmark-bmenu-execute-deletions]." (interactive) (beginning-of-line) - (if (Bookmark-menu-check-position) + (if (bookmark-bmenu-check-position) (let ((buffer-read-only nil)) (delete-char 1) (insert ?D) - (forward-line 1)))) + (forward-line 1) + (bookmark-bmenu-check-position)))) + -(defun Bookmark-menu-delete-backwards () - "Mark bookmark on this line to be deleted by \\\\[Bookmark-menu-execute] command. -Then move up one line" +(defun bookmark-bmenu-delete-backwards () + "Mark bookmark on this line to be deleted, then move up one line. +To carry out the deletions that you've marked, use \\\\[bookmark-bmenu-execute-deletions]." (interactive) - (Bookmark-menu-delete) + (bookmark-bmenu-delete) (forward-line -2) - (if (Bookmark-menu-check-position) - (forward-line 1))) + (if (bookmark-bmenu-check-position) + (forward-line 1)) + (bookmark-bmenu-check-position)) + -(defun Bookmark-menu-execute () +(defun bookmark-bmenu-execute-deletions () "Delete bookmarks marked with \\\\[Buffer-menu-delete] commands." (interactive) - (let ((hide-em Bookmark-menu-toggle-filenames)) - (if hide-em (Bookmark-menu-hide-filenames)) - (setq Bookmark-menu-toggle-filenames nil) + (message "Deleting bookmarks...") + (let ((hide-em bookmark-bmenu-toggle-filenames) + (o-point (point)) + (o-str (save-excursion + (beginning-of-line) + (if (looking-at "^D") + nil + (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) - (let ((deaders ())) - (while (re-search-forward "^D" (point-max) t) - (setq deaders (cons (Bookmark-menu-bookmark) deaders))) - (mapcar (lambda (str) - (setq bookmark-alist - (delq (assoc str bookmark-alist) bookmark-alist))) - deaders)) - (list-bookmarks) - (goto-char (point-min)) - (forward-line 2) - (setq Bookmark-menu-toggle-filenames hide-em) - (if Bookmark-menu-toggle-filenames - (Bookmark-menu-toggle-filenames t)))) - -(defun Bookmark-menu-rename () + (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)) + (search-forward o-str) + (beginning-of-line) + (forward-char o-col)) + (goto-char o-point)) + (beginning-of-line) + (setq bookmark-alist-modification-count + (1+ bookmark-alist-modification-count)) + (if (bookmark-time-to-save-p) + (bookmark-save)) + (message "Deleting bookmarks...done") + )) + + +(defun bookmark-bmenu-rename () "Rename bookmark on current line. Prompts for a new name." (interactive) - (if (Bookmark-menu-check-position) - (let ((bmrk (Bookmark-menu-bookmark)) + (if (bookmark-bmenu-check-position) + (let ((bmrk (bookmark-bmenu-bookmark)) (thispoint (point))) (bookmark-rename bmrk) - (list-bookmarks) + (bookmark-bmenu-list) (goto-char thispoint)))) -(defun Bookmark-menu-locate () + +(defun bookmark-bmenu-locate () "Display location of this bookmark. Displays in the minibuffer." (interactive) - (if (Bookmark-menu-check-position) - (let ((bmrk (Bookmark-menu-bookmark))) - (message (bookmark-locate bmrk t))))) - -;;;; bookmark menu bar stuff ;;;; - -(defvar bookmark-menu-bar-length 70 - "*Maximum length of a bookmark name displayed on a popup menu.") - -(defun bookmark-make-menu-bar-alist () - (bookmark-try-default-file) - (bookmark-maybe-sort-alist) - (if bookmark-alist - (mapcar (lambda (cell) - (let ((str (car cell))) - (cons - (if (> (length str) bookmark-menu-bar-length) - (substring str 0 bookmark-menu-bar-length) - str) - str))) - bookmark-alist) - (error "No bookmarks currently set."))) - -(defun bookmark-make-menu-bar-with-function (func-sym - menu-label - menu-str event) + (if (bookmark-bmenu-check-position) + (let ((bmrk (bookmark-bmenu-bookmark))) + (message (bookmark-location bmrk))))) + + + +;;; Menu bar stuff. Prefix is "bookmark-menu". + +(defun bookmark-menu-build-paned-menu (name entries) + "Build a multi-paned menu named NAME from the strings in ENTRIES. +That is, ENTRIES is a list of strings which appear as the choices +in the menu. The number of panes depends on the number of entries. +The visible entries are truncated to `bookmark-menu-length', but the +strings returned are not." + (let* ((f-height (/ (frame-height) 2)) + (pane-list + (let (temp-pane-list + (iter 0)) + (while entries + (let (lst + (count 0)) + (while (and (< count f-height) entries) + (let ((str (car entries))) + (setq lst (cons + (cons + (if (> (length str) bookmark-menu-length) + (substring str 0 bookmark-menu-length) + str) + str) + lst)) + (setq entries (cdr entries)) + (setq count (1+ count)))) + (setq iter (1+ iter)) + (setq + temp-pane-list + (cons + (cons + (format "-*- %s (%d) -*-" name iter) + (nreverse lst)) + temp-pane-list)))) + (nreverse temp-pane-list)))) + + ;; Return the menu: + (cons (concat "-*- " name " -*-") pane-list))) + + +(defun bookmark-menu-popup-paned-menu (event name entries) + "Pop up multi-paned menu at EVENT, return string chosen from ENTRIES. +That is, ENTRIES is a list of strings which appear as the choices +in the menu. +The number of panes depends on the number of entries." + (interactive "e") + (x-popup-menu event (bookmark-menu-build-paned-menu name entries))) + + +(defun bookmark-menu-popup-paned-bookmark-menu (event name) + "Pop up menu of bookmarks, return chosen bookmark. +Pop up at EVENT, menu's name is NAME. +The number of panes depends on the number of bookmarks." + (bookmark-menu-popup-paned-menu event name (bookmark-all-names))) + + +(defun bookmark-popup-menu-and-apply-function (func-sym menu-label event) ;; help function for making menus that need to apply a bookmark ;; function to a string. - (let* ((menu (bookmark-make-menu-bar-alist)) - (str (x-popup-menu event - (list menu-label - (cons menu-str menu))))) - (if str (apply func-sym (list str))))) + (let* ((choice (bookmark-menu-popup-paned-bookmark-menu + event menu-label))) + (if choice (apply func-sym (list choice))))) + ;;;###autoload -(defun bookmark-menu-bar-insert (event) +(defun bookmark-menu-insert (event) "Insert the text of the file pointed to by bookmark BOOKMARK. You may have a problem using this function if the value of variable `bookmark-alist' is nil. If that happens, you need to load in some bookmarks. See help on function `bookmark-load' for more about -this." +this. + +Warning: this function only takes an EVENT as argument. Use the +corresponding bookmark function from Lisp \(the one without the +\"-menu-\" in its name\)." (interactive "e") - (bookmark-make-menu-bar-with-function 'bookmark-insert - "Bookmark Insert Menu" - "--- Insert Contents ---" - event)) + (bookmark-popup-menu-and-apply-function + 'bookmark-insert "Insert Bookmark Contents" event)) + ;;;###autoload -(defun bookmark-menu-bar-jump (event) +(defun bookmark-menu-jump (event) "Jump to bookmark BOOKMARK (a point in some file). You may have a problem using this function if the value of variable `bookmark-alist' is nil. If that happens, you need to load in some bookmarks. See help on function `bookmark-load' for more about -this." +this. + +Warning: this function only takes an EVENT as argument. Use the +corresponding bookmark function from Lisp \(the one without the +\"-menu-\" in its name\)." (interactive "e") - (bookmark-make-menu-bar-with-function 'bookmark-jump - "Bookmark Jump Menu" - "--- Jump to Bookmark ---" - event)) + (bookmark-popup-menu-and-apply-function + 'bookmark-jump "Jump to Bookmark" event)) + ;;;###autoload -(defun bookmark-menu-bar-locate (event) +(defun bookmark-menu-locate (event) "Insert the name of the file associated with BOOKMARK. -\(This is not the same as the contents of that file\)." +\(This is not the same as the contents of that file\). + +Warning: this function only takes an EVENT as argument. Use the +corresponding bookmark function from Lisp \(the one without the +\"-menu-\" in its name\)." (interactive "e") - (bookmark-make-menu-bar-with-function 'bookmark-locate - "Bookmark Locate Menu" - "--- Insert Location ---" - event)) + (bookmark-popup-menu-and-apply-function + 'bookmark-insert-location "Insert Bookmark Location" event)) + ;;;###autoload -(defun bookmark-menu-bar-rename (event) +(defun bookmark-menu-rename (event) "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 @@ -1235,79 +2173,102 @@ 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. While you are entering the new name, consecutive C-w's insert -consectutive words from the text of the buffer into the new bookmark -name, and C-v inserts the name of the file." +consecutive words from the text of the buffer into the new bookmark +name. + +Warning: this function only takes an EVENT as argument. Use the +corresponding bookmark function from Lisp \(the one without the +\"-menu-\" in its name\)." (interactive "e") - (bookmark-make-menu-bar-with-function 'bookmark-rename - "Bookmark Rename Menu" - "--- Rename Bookmark ---" - event)) + (bookmark-popup-menu-and-apply-function + 'bookmark-rename "Rename Bookmark" event)) + ;;;###autoload -(defun bookmark-menu-bar-delete (event) +(defun bookmark-menu-delete (event) "Delete the bookmark named NAME from the bookmark list. Removes only the first instance of a bookmark with that name. If there are one or more other bookmarks with the same name, they will not be deleted. Defaults to the \"current\" bookmark \(that is, the -one most recently used in this file, if any\)." +one most recently used in this file, if any\). + +Warning: this function only takes an EVENT as argument. Use the +corresponding bookmark function from Lisp \(the one without the +\"-menu-\" in its name\)." (interactive "e") - (bookmark-make-menu-bar-with-function 'bookmark-delete - "Bookmark Delete Menu" - "--- Delete Bookmark ---" - event)) + (bookmark-popup-menu-and-apply-function + 'bookmark-delete "Delete Bookmark" event)) + ;; Thanks to Roland McGrath for fixing menubar.el so that the ;; following works, and for explaining what to do to make it work. +;; We MUST autoload EACH form used to set up this variable's value, so +;; that the whole job is done in loaddefs.el. + +;; Emacs menubar stuff. + ;;;###autoload -(defvar menu-bar-bookmark-map (make-sparse-keymap "Bookmark functions.")) +(defvar menu-bar-bookmark-map (make-sparse-keymap "Bookmark functions")) ;;;###autoload -(fset 'menu-bar-bookmark-map (symbol-value 'menu-bar-bookmark-map)) +(defalias 'menu-bar-bookmark-map (symbol-value 'menu-bar-bookmark-map)) + +;; make bookmarks appear toward the right side of the menu. +(if (boundp 'menu-bar-final-items) + (if menu-bar-final-items + (setq menu-bar-final-items + (cons 'bookmark menu-bar-final-items))) + (setq menu-bar-final-items '(bookmark))) ;;;###autoload (define-key menu-bar-bookmark-map [load] - '("Load a bookmark file" . bookmark-load)) + '("Load a Bookmark File..." . bookmark-load)) ;;;###autoload (define-key menu-bar-bookmark-map [write] - '("Write \(to another file\)" . bookmark-write)) + '("Save Bookmarks As..." . bookmark-write)) ;;;###autoload (define-key menu-bar-bookmark-map [save] - '("Save \(in default file\)" . bookmark-save)) + '("Save Bookmarks" . bookmark-save)) ;;;###autoload (define-key menu-bar-bookmark-map [edit] - '("Edit Bookmark List" . list-bookmarks)) + '("Edit Bookmark List" . bookmark-bmenu-list)) ;;;###autoload (define-key menu-bar-bookmark-map [delete] - '("Delete bookmark" . bookmark-menu-bar-delete)) + '("Delete Bookmark" . bookmark-menu-delete)) ;;;###autoload (define-key menu-bar-bookmark-map [rename] - '("Rename bookmark" . bookmark-menu-bar-rename)) + '("Rename Bookmark" . bookmark-menu-rename)) ;;;###autoload (define-key menu-bar-bookmark-map [locate] - '("Insert location" . bookmark-menu-bar-locate)) + '("Insert Location" . bookmark-menu-locate)) ;;;###autoload (define-key menu-bar-bookmark-map [insert] - '("Insert contents" . bookmark-menu-bar-insert)) + '("Insert Contents" . bookmark-menu-insert)) ;;;###autoload (define-key menu-bar-bookmark-map [set] - '("Set bookmark" . bookmark-set)) + '("Set Bookmark" . bookmark-set)) ;;;###autoload (define-key menu-bar-bookmark-map [jump] - '("Jump to bookmark" . bookmark-menu-bar-jump)) + '("Jump to Bookmark" . bookmark-menu-jump)) + +;;;; end bookmark menu stuff ;;;; -(fset 'menu-bar-bookmark-map (symbol-value 'menu-bar-bookmark-map)) + +;;; Load Hook +(defvar bookmark-load-hook nil + "Hook to run at the end of loading bookmark.") -;;;; end bookmark menu-bar stuff ;;;; +(run-hooks 'bookmark-load-hook) (provide 'bookmark)