X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/4c0b5ad1cba82d3e8dbc16d86cdb897e22be955c..2d4e1e6e5a3877adc1b13d47881e6e74b6665c61:/lisp/bookmark.el diff --git a/lisp/bookmark.el b/lisp/bookmark.el index c17d6db4c4..65f117a041 100644 --- a/lisp/bookmark.el +++ b/lisp/bookmark.el @@ -1,19 +1,12 @@ ;;; bookmark.el --- set bookmarks, maybe annotate them, jump to them later. -;; Copyright (C) 1993, 1994, 1995 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 -;; Author's Update Number: 2.6.8 ;; Keywords: bookmarks, placeholders, annotations -;;; Summary: -;; 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. - -;;; Copyright info: ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify @@ -27,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 @@ -46,7 +47,7 @@ ;; 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. @@ -54,7 +55,7 @@ ;; 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!) @@ -65,18 +66,21 @@ ;; Based on info-bookmark.el, by Karl Fogel and Ken Olstad ;; . +;; 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? - - -(require 'pp) - ;;;; Code: +(require 'pp) + ;;; Misc comments: ;; ;; If variable bookmark-use-annotations is non-nil, an annotation is @@ -87,30 +91,147 @@ ;; 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)) +;; This variable is probably obsolete now... +(or (boundp 'baud-rate) + ;; some random value higher than 9600 + (setq baud-rate 19200)) + +;; XEmacs apparently call this `buffer-substring-without-properties', +;; sigh. +(or (fboundp 'buffer-substring-no-properties) + (if (fboundp 'buffer-substring-without-properties) + (fset 'buffer-substring-no-properties + 'buffer-substring-without-properties) + (fset 'buffer-substring-no-properties 'buffer-substring))) ;;; Keymap stuff: -;; 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 (symbolp (key-binding "\C-xr")) - nil - (progn (define-key ctl-x-map "rb" 'bookmark-jump) - (define-key ctl-x-map "rm" 'bookmark-set) - (define-key ctl-x-map "rl" 'bookmark-bmenu-list))) -;; define the map, so it can be bound by those who desire to do so: +;; 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 @@ -120,10 +241,6 @@ so that you have a bookmark prefix, just use `global-set-key' and bind a key of your choice to `bookmark-map'. All interactive bookmark functions have a binding in this keymap.") -(defvar bookmark-use-annotations nil - "*If non-nil, saving a bookmark will query for an annotation in a -buffer.") - ;;;###autoload (define-prefix-command 'bookmark-map) @@ -167,7 +284,24 @@ buffer.") (defvar bookmark-alist () "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) @@ -193,65 +327,10 @@ 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-default-file, which is `~/.emacs.bmk' by default.") - - (defvar bookmark-alist-modification-count 0 "Number of modifications to bookmark list since it was last saved.") -(defconst bookmark-old-default-file "~/.emacs-bkmrks" - "*The .emacs.bmk file used to be called this.") - - -;; defvarred to avoid a compilation warning: -(defvar bookmark-file nil - "Old name for `bookmark-default-file'.") - -(defvar bookmark-default-file - (if bookmark-file - ;; In case user set `bookmark-file' in her .emacs: - bookmark-file - (if (eq system-type 'ms-dos) - "~/emacs.bmk" ; Cannot have initial dot [Yuck!] - "~/.emacs.bmk")) - "*File in which to save bookmarks by default.") - - -(defvar bookmark-version-control 'nospecial - "This variable controls whether or not to make numbered backups of -the master bookmark file. It can have four values: t, nil, never, and -nospecial. The first three have the same meaning that they do for the -variable version-control, and the final value nospecial means just use -the value of version-control.") - - -(defvar bookmark-completion-ignore-case t - "*Non-nil means bookmark functions ignore case in completion.") - - -(defvar bookmark-sort-flag t - "*Non-nil means that bookmarks will be displayed sorted by bookmark -name. Otherwise they will be displayed in LIFO order (that is, most -recently set ones come first, oldest ones come last).") - - (defvar bookmark-search-size 16 "Length of the context strings recorded on either side of a bookmark.") @@ -269,7 +348,7 @@ recently set ones come first, oldest ones come last).") ;; Everyone else should go through them. (defun bookmark-name-from-full-record (full-record) - "Return name of BOOKMARK \(an alist element instead of a string\)." + "Return name of FULL-RECORD \(an alist element instead of a string\)." (car full-record)) @@ -295,7 +374,9 @@ That is, all information but the name." (defun bookmark-set-name (bookmark newname) "Set BOOKMARK's name to NEWNAME." - (setcar (bookmark-get-bookmark bookmark) newname)) + (setcar + (if (stringp bookmark) (bookmark-get-bookmark bookmark) bookmark) + newname)) (defun bookmark-get-annotation (bookmark) @@ -304,7 +385,7 @@ That is, all information but the name." (defun bookmark-set-annotation (bookmark ann) - "Set the annotation of BOOKMARK." + "Set the annotation of BOOKMARK to ANN." (let ((cell (assq 'annotation (bookmark-get-bookmark-record bookmark)))) (if cell (setcdr cell ann) @@ -371,6 +452,7 @@ That is, all information but the name." (defun bookmark-get-info-node (bookmark) + "Get the info node associated with BOOKMARK." (cdr (assq 'info-node (bookmark-get-bookmark-record bookmark)))) @@ -381,7 +463,11 @@ That is, all information but the name." (if cell (setcdr cell node) (nconc (bookmark-get-bookmark-record bookmark) - (list (cons 'info-node node)))))) + (list (cons 'info-node node))))) + + (message "%S" (assq 'info-node (bookmark-get-bookmark-record bookmark))) + (sit-for 4) + ) (defvar bookmark-history nil @@ -421,64 +507,80 @@ menus, so `completing-read' never gets a chance to set `bookmark-history'." (setq bookmark-history (cons (, string) bookmark-history))))) -(defun bookmark-make (str &optional annotation overwrite) +(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." +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) - (if (and (bookmark-get-bookmark str) (not overwrite)) - ;; already existing boookmark under that name and - ;; no prefix arg means just overwrite old bookmark - (setcdr (bookmark-get-bookmark str) - (list (bookmark-make-cell annotation))) - - ;; 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...) + (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))) - (setq bookmark-alist - (cons - (list str - (bookmark-make-cell annotation)) - 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 (annotation) - "Return the record part of a bookmark. + ;; 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 will change soon. -Takes ANNOTATION as an argument." - (` ((filename . (, (bookmark-buffer-file-name))) - (front-context-string - . (, (if (>= (- (point-max) (point)) bookmark-search-size) - ;; strip text props via `format': - (let ((string - (buffer-substring - (point) - (+ (point) bookmark-search-size)))) - (set-text-properties 0 (length string) nil string) - string) - nil))) - (rear-context-string - . (, (if (>= (- (point) (point-min)) bookmark-search-size) - ;; strip text props via `format': - (let ((string - (buffer-substring - (point) - (- (point) bookmark-search-size)))) - (set-text-properties 0 (length string) nil string) - string) - nil))) - (position . (, (point))) - (annotation . (, annotation))))) +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 @@ -525,11 +627,9 @@ Takes ANNOTATION as an argument." ;; 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 +;; ANNOTATION is the annotation for the bookmark; it may not exist ;; (for backward compatibility), be nil (no annotation), or be a ;; string. -;; -;; ANNOTATION is an annotation for the bookmark. (defconst bookmark-file-format-version 1 @@ -557,11 +657,11 @@ affect point." (forward-char -1) (read (current-buffer))) ;; Else no hope of getting information here. - (error "Not bookmark format."))))) + (error "Not bookmark format"))))) (defun bookmark-upgrade-version-0-alist (old-list) - "Upgrade a version 0 alist to the current version." + "Upgrade a version 0 alist OLD-LIST to the current version." (mapcar (lambda (bookmark) (let* ((name (car bookmark)) @@ -593,7 +693,7 @@ This expects to be called from point-min in a bookmark file." (pp new-list (current-buffer)) (save-buffer)) (goto-char (point-min)) - (message "Upgrading bookmark format from 0 to %d... done." + (message "Upgrading bookmark format from 0 to %d...done" bookmark-file-format-version) ) @@ -623,11 +723,11 @@ This expects to be called from point-min in a bookmark file." ((= version 0) (bookmark-upgrade-file-format-from-0)) (t - (error "Bookmark file format version strangeness."))))) + (error "Bookmark file format version strangeness"))))) (defun bookmark-insert-file-format-version-stamp () - "Insert text indicating current version of bookmark file-format." + "Insert text indicating current version of bookmark file format." (insert (format ";;;; Emacs Bookmark Format Version %d ;;;;\n" bookmark-file-format-version)) @@ -643,8 +743,9 @@ This expects to be called from point-min in a bookmark file." ;;; Core code: ;;;###autoload -(defun bookmark-set (&optional parg) - "Set a bookmark named NAME inside a 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 @@ -664,10 +765,10 @@ 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") + (interactive (list nil current-prefix-arg)) (or (bookmark-buffer-file-name) - (error "Buffer not visiting a file or directory.")) + (error "Buffer not visiting a file or directory")) (bookmark-maybe-load-default-file) @@ -678,28 +779,29 @@ the list of bookmarks.\)" (let* ((default (or bookmark-current-bookmark (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-u" - 'bookmark-insert-current-bookmark)) - now-map))) + (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) - (progn - (bookmark-make str annotation parg) - ;; In Info, there's a little more information to record: - (if (eq major-mode 'Info-mode) - (bookmark-set-info-node str Info-current-node)) - (setq bookmark-current-bookmark str) - (bookmark-bmenu-surreptitiously-rebuild-list) - (goto-char bookmark-current-point))))) + (bookmark-make str annotation parg (bookmark-info-current-node)) + (setq bookmark-current-bookmark str) + (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) @@ -721,18 +823,19 @@ Does not affect the kill-ring." (defun bookmark-send-annotation () - "After remove lines beginning with '#', use the contents of this buffer -as the annotation for a bookmark, and store it in the bookmark list with + "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.")) + (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-substring (point-min) (point-max))) + (let ((annotation (buffer-string)) (parg bookmark-annotation-paragraph) (bookmark bookmark-annotation-name) (pt bookmark-annotation-point) @@ -745,7 +848,7 @@ the bookmark (and file, and point) specified in buffer local variables." (save-excursion (pop-to-buffer buf) (goto-char pt) - (bookmark-make bookmark annotation parg) + (bookmark-make bookmark annotation parg (bookmark-info-current-node)) (setq bookmark-current-bookmark bookmark)) (bookmark-bmenu-surreptitiously-rebuild-list) (goto-char bookmark-current-point)) @@ -762,13 +865,12 @@ the bookmark (and file, and point) specified in buffer local variables." (defvar bookmark-read-annotation-text-func 'bookmark-default-annotation-text - "A variable containing a function which returns the text to insert -into an annotation compisition buffer. It takes the name of the bookmark, -as a string, as an arg.") - + "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. @@ -793,8 +895,8 @@ the annotation. (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." + "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*")) @@ -823,24 +925,22 @@ When you have finished composing, type \\[bookmark-send-annotation]. (setq major-mode 'bookmark-edit-annotation-mode) (insert (funcall bookmark-read-annotation-text-func bookmark)) (let ((annotation (bookmark-get-annotation bookmark))) - (if (and (not (eq annotation nil)) - (not (string-equal annotation ""))) + (if (and annotation (not (string-equal annotation ""))) (insert annotation))) (run-hooks 'text-mode-hook)) (defun bookmark-send-edited-annotation () - "After remove lines beginning with '#', use the contents of this buffer -as the new annotation for a bookmark." + "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.")) + (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-substring (point-min) (point-max))) + (let ((annotation (buffer-string)) (bookmark bookmark-annotation-name)) (bookmark-set-annotation bookmark annotation) (bookmark-bmenu-surreptitiously-rebuild-list) @@ -857,8 +957,8 @@ as the new annotation for a 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 @@ -868,8 +968,8 @@ as the new annotation for a bookmark." (defun bookmark-insert-buffer-name () - ;; insert the name (sans path) of the current file into the bookmark - ;; name that is being set. + "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 @@ -909,9 +1009,9 @@ In Info, return the current node." (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))) @@ -933,7 +1033,6 @@ For example, if this is a Info buffer, return the Info file's name." (defun bookmark-maybe-load-default-file () (and (not bookmarks-already-loaded) (null bookmark-alist) - (prog2 (and ;; Possibly the old bookmark file, "~/.emacs-bkmrks", needs @@ -946,9 +1045,8 @@ For example, if this is a Info buffer, return the Info file's name." t) (file-readable-p (expand-file-name bookmark-default-file)) - (progn - (bookmark-load bookmark-default-file t t) - (setq bookmarks-already-loaded t)))) + (bookmark-load bookmark-default-file t t) + (setq bookmarks-already-loaded t))) (defun bookmark-maybe-sort-alist () @@ -962,7 +1060,7 @@ For example, if this is a Info buffer, return the Info file's name." ;;;###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 @@ -975,14 +1073,15 @@ 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 str) - (let ((cell (bookmark-jump-noselect str))) + (bookmark-maybe-historicize-string bookmark) + (let ((cell (bookmark-jump-noselect bookmark))) (and cell (switch-to-buffer (car cell)) (goto-char (cdr cell)) - ;; if there is an annotation for this bookmark, - ;; show it in a buffer. - (bookmark-show-annotation str)))) + (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) @@ -1014,132 +1113,145 @@ of the old one in the permanent bookmark record." (and (file-exists-p altname) altname))))) (save-excursion - (if info-node - ;; Info nodes must be visited with care. - (progn - (require 'info) - (Info-find-node file info-node)) - ;; Else no Info. Can do an ordinary find-file: - (set-buffer (find-file-noselect file)) - (goto-char place)) - - ;; Go searching forward first. Then, if forward-str exists and - ;; was found in the file, we can search backward for behind-str. - ;; Rationale is that if text was inserted between the two in the - ;; file, it's better to be put before it so you can read it, - ;; rather than after and remain perhaps unaware of the changes. - (if forward-str - (if (search-forward forward-str (point-max) t) - (backward-char (length forward-str)))) - (if behind-str - (if (search-backward behind-str (point-min) t) - (forward-char (length behind-str)))) - ;; 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; consider removing it \(%s\)." str) - nil))))) + (save-window-excursion + (if info-node + ;; Info nodes must be visited with care. + (progn + (require 'info) + (Info-find-node file info-node)) + ;; Else no Info. Can do an ordinary find-file: + (set-buffer (find-file-noselect file)) + (goto-char place)) + + ;; Go searching forward first. Then, if forward-str exists and + ;; was found in the file, we can search backward for behind-str. + ;; Rationale is that if text was inserted between the two in the + ;; file, it's better to be put before it so you can read it, + ;; rather than after and remain perhaps unaware of the changes. + (if forward-str + (if (search-forward forward-str (point-max) t) + (goto-char (match-beginning 0)))) + (if behind-str + (if (search-backward behind-str (point-min) t) + (goto-char (match-end 0)))) + ;; added by db + (setq bookmark-current-bookmark str) + (cons (current-buffer) (point)))) + + ;; Else unable to find the marked file, so ask if user wants to + ;; relocate the bookmark, else remind them to consider deletion. + (ding) + (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 (str) - "Relocate BOOKMARK -- prompts for a filename, and makes an already -existing bookmark point to that file, instead of the one it used to -point at. Useful when a file has been renamed after a bookmark was -set in it." +(defun bookmark-relocate (bookmark) + "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 str) + (bookmark-maybe-historicize-string bookmark) (bookmark-maybe-load-default-file) - (let* ((bmrk-filename (bookmark-get-filename str)) + (let* ((bmrk-filename (bookmark-get-filename bookmark)) (newloc (expand-file-name (read-file-name - (format "Relocate %s to: " str) + (format "Relocate %s to: " bookmark) (file-name-directory bmrk-filename))))) - (bookmark-set-filename str newloc))) + (bookmark-set-filename bookmark newloc) + (bookmark-bmenu-surreptitiously-rebuild-list))) ;;;###autoload -(defun bookmark-insert-location (str &optional no-history) +(defun bookmark-insert-location (bookmark &optional no-history) "Insert the name of the file associated with BOOKMARK. 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 str)) - (insert (bookmark-location str))) + (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 (str) +(defun bookmark-location (bookmark) "Return the name of the file associated with BOOKMARK." (bookmark-maybe-load-default-file) - (bookmark-get-filename str)) + (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 +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) - (progn - (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)))) - (progn - (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)))))) + + (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 (bookmark-completing-read "Insert bookmark contents")) - (bookmark-maybe-historicize-string str) + (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))) @@ -1161,7 +1273,7 @@ probably because we were called from there." (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 + ;; occurrence has been deleted (or (bookmark-get-bookmark bookmark-current-bookmark) (setq bookmark-current-bookmark nil))) ;; Don't rebuild the list @@ -1192,9 +1304,8 @@ probably because we were called from there." ;;;###autoload (defun bookmark-write () - "Write bookmarks to a file \(for which the user will be prompted -interactively\). Don't use this in Lisp programs; use bookmark-save -instead." + "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-maybe-load-default-file) (bookmark-save t)) @@ -1204,7 +1315,8 @@ instead." (defun bookmark-save (&optional parg file) "Save currently defined bookmarks. Saves by default in the file defined by the variable -`bookmark-default-file'. With a prefix arg, save it in file FILE. +`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 @@ -1242,7 +1354,7 @@ for a file, defaulting to the file defined by variable (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)) @@ -1259,15 +1371,47 @@ for a file, defaulting to the file defined by variable (write-file file) (kill-buffer (current-buffer)) (if (>= baud-rate 9600) - (message (format "Saving bookmarks to file %s... done." file))) + (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. @@ -1276,7 +1420,12 @@ 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.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 (list (read-file-name (format "Load bookmarks from: (%s) " @@ -1290,7 +1439,7 @@ explicitly." (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)) @@ -1298,18 +1447,24 @@ explicitly." (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 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 (format "Invalid bookmark list in %s." file)))) + (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))) @@ -1323,19 +1478,6 @@ explicitly." (defvar bookmark-bmenu-hidden-bookmarks ()) -(defvar 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].") - - -(defvar 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: - -\(setq bookmark-bmenu-toggle-filenames nil\)") - - (defvar bookmark-bmenu-mode-map nil) @@ -1343,20 +1485,21 @@ following in your .emacs: nil (setq bookmark-bmenu-mode-map (make-keymap)) (suppress-keymap bookmark-bmenu-mode-map t) - (define-key bookmark-bmenu-mode-map "q" 'bookmark-bmenu-quit) + (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 "\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 "\C-k" 'bookmark-bmenu-delete) (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) @@ -1370,7 +1513,9 @@ following in your .emacs: (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 "e" 'bookmark-bmenu-edit-annotation) + (define-key bookmark-bmenu-mode-map [mouse-2] + 'bookmark-bmenu-other-window-with-mouse)) @@ -1413,15 +1558,23 @@ deletion, or > if it is flagged for displaying." (bookmark-maybe-sort-alist) (mapcar (lambda (full-record) - ;; if a bookmark has an annotation, preceed it with a "*" + ;; 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 (not (eq annotation nil)) - (not (string-equal annotation ""))) + (if (and annotation (not (string-equal annotation ""))) (insert " *") (insert " ")) - (insert (concat (bookmark-name-from-full-record full-record) "\n")))) + (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) @@ -1440,7 +1593,7 @@ deletion, or > if it is flagged for displaying." "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 names preceeded by a \"*\" have annotations. +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. @@ -1457,7 +1610,7 @@ Bookmark names preceeded by a \"*\" have annotations. \\[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 marked bookmarks. +\\[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-bmenu-load] -- load in a file of bookmarks (prompts for file.) @@ -1477,12 +1630,12 @@ Bookmark names preceeded by a \"*\" have annotations. (run-hooks 'bookmark-bmenu-mode-hook)) -(defun bookmark-bmenu-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 + (show (setq bookmark-bmenu-toggle-filenames nil) (bookmark-bmenu-show-filenames) (setq bookmark-bmenu-toggle-filenames t)) @@ -1507,8 +1660,13 @@ Optional argument SHOW means show them unconditionally." (let ((bmrk (bookmark-bmenu-bookmark))) (setq bookmark-bmenu-hidden-bookmarks (cons bmrk bookmark-bmenu-hidden-bookmarks)) - (move-to-column bookmark-bmenu-file-column t) - (delete-region (point) (progn (end-of-line) (point))) + (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 " ") ;; Pass the NO-HISTORY arg: (bookmark-insert-location bmrk t) @@ -1534,28 +1692,32 @@ Optional argument SHOW means show them unconditionally." (while bookmark-bmenu-hidden-bookmarks (move-to-column bookmark-bmenu-bookmark-column t) (bookmark-kill-line) - (insert (car bookmark-bmenu-hidden-bookmarks)) + (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-bmenu-check-position () - ;; Returns t if on a line with a bookmark. - ;; Otherwise, repositions and returns t. - ;; written by David Hughes - ;; Mucho thanks, David! -karl + ;; 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-bmenu-bookmark () @@ -1574,7 +1736,7 @@ Optional argument SHOW means show them unconditionally." (beginning-of-line) (forward-char bookmark-bmenu-bookmark-column) (prog1 - (buffer-substring (point) + (buffer-substring-no-properties (point) (progn (end-of-line) (point))) @@ -1587,17 +1749,15 @@ Optional argument SHOW means show them unconditionally." "Display the annotation for bookmark named BOOKMARK in a buffer, if an annotation exists." (let ((annotation (bookmark-get-annotation bookmark))) - (if (and (not (eq annotation nil)) - (not (string-equal annotation ""))) - (progn - (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))))))) + (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 () @@ -1610,7 +1770,7 @@ if an annotation exists." (let* ((name (bookmark-name-from-full-record full-record)) (ann (bookmark-get-annotation name))) (insert (concat name ":\n")) - (if (and (not (eq ann nil)) (not (string-equal ann ""))) + (if (and ann (not (string-equal ann ""))) ;; insert the annotation, indented by 4 spaces. (progn (save-excursion (insert ann)) @@ -1625,14 +1785,15 @@ if an annotation exists." (defun bookmark-bmenu-mark () - "Mark bookmark on this line to be displayed by \\\\[bookmark-bmenu-select] command." + "Mark bookmark on this line to be displayed by \\\\[bookmark-bmenu-select]." (interactive) (beginning-of-line) (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-bmenu-select () @@ -1651,20 +1812,19 @@ You can mark bookmarks with the \\\\[bookmark-bmenu-mar (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))))) @@ -1706,8 +1866,11 @@ With a prefix arg, prompts for a file to save them in." (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)))) @@ -1723,10 +1886,45 @@ With a prefix arg, prompts for a file to save them in." (interactive) (let ((bookmark (bookmark-bmenu-bookmark))) (if (bookmark-bmenu-check-position) - (let ((buff (car (bookmark-jump-noselect bookmark)))) + (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) + (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-bmenu-show-annotation () "Show the annotation for the current bookmark in another window." @@ -1750,28 +1948,9 @@ With a prefix arg, prompts for a file to save them in." (bookmark-edit-annotation bookmark)))) -(defun bookmark-bmenu-switch-other-window () - "Make the other window select this line's bookmark. -The current window remains selected." - (interactive) - (let ((bookmark (bookmark-bmenu-bookmark))) - (if (bookmark-bmenu-check-position) - (let ((buff (car (bookmark-jump-noselect bookmark)))) - (display-buffer buff) - (bookmark-show-annotation bookmark))))) - - -(defun bookmark-bmenu-quit () - "Quit the bookmark menu." - (interactive) - (let ((buffer (current-buffer))) - (switch-to-buffer (other-buffer)) - (bury-buffer buffer))) - - (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-bmenu-check-position) @@ -1782,7 +1961,8 @@ 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-bmenu-backup-unmark () @@ -1792,33 +1972,38 @@ Optional ARG means move up." (if (bookmark-bmenu-check-position) (progn (bookmark-bmenu-unmark) - (forward-line -1)))) + (forward-line -1) + (bookmark-bmenu-check-position)))) (defun bookmark-bmenu-delete () - "Mark bookmark on this line to be deleted by \\\\[bookmark-bmenu-execute-deletions] command." + "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-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-bmenu-delete-backwards () - "Mark bookmark on this line to be deleted by \\\\[bookmark-bmenu-execute-deletions] command -and then move up one line" + "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-bmenu-delete) (forward-line -2) (if (bookmark-bmenu-check-position) - (forward-line 1))) + (forward-line 1)) + (bookmark-bmenu-check-position)) (defun bookmark-bmenu-execute-deletions () "Delete bookmarks marked with \\\\[Buffer-menu-delete] commands." (interactive) + (message "Deleting bookmarks...") (let ((hide-em bookmark-bmenu-toggle-filenames) (o-point (point)) (o-str (save-excursion @@ -1850,7 +2035,9 @@ and then move up one line" (setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count)) (if (bookmark-time-to-save-p) - (bookmark-save)))) + (bookmark-save)) + (message "Deleting bookmarks...done") + )) (defun bookmark-bmenu-rename () @@ -1875,10 +2062,6 @@ and then move up one line" ;;; Menu bar stuff. Prefix is "bookmark-menu". -(defvar bookmark-menu-length 70 - "*Maximum length of a bookmark name displayed on a popup 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 @@ -1941,36 +2124,52 @@ The number of panes depends on the number of bookmarks." (if choice (apply func-sym (list choice))))) +;;;###autoload (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-popup-menu-and-apply-function 'bookmark-insert "Insert Bookmark Contents" event)) +;;;###autoload (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-popup-menu-and-apply-function 'bookmark-jump "Jump to Bookmark" event)) +;;;###autoload (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-popup-menu-and-apply-function 'bookmark-insert-location "Insert Bookmark Location" event)) +;;;###autoload (defun bookmark-menu-rename (event) "Change the name of OLD-BOOKMARK to NEWNAME. If called from keyboard, prompts for OLD-BOOKMARK and NEWNAME. @@ -1981,19 +2180,28 @@ 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." +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-popup-menu-and-apply-function 'bookmark-rename "Rename Bookmark" event)) +;;;###autoload (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-popup-menu-and-apply-function 'bookmark-delete "Delete Bookmark" event)) @@ -2002,8 +2210,16 @@ one most recently used in this file, if any\)." ;; Thanks to Roland McGrath for fixing menubar.el so that the ;; following works, and for explaining what to do to make it work. -(defvar menu-bar-bookmark-map (make-sparse-keymap "Bookmark functions.")) +;; 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")) + +;;;###autoload +(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) @@ -2012,39 +2228,45 @@ one most recently used in this file, if any\)." (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" . bookmark-bmenu-list)) +;;;###autoload (define-key menu-bar-bookmark-map [delete] - '("Delete bookmark" . bookmark-menu-delete)) + '("Delete Bookmark" . bookmark-menu-delete)) +;;;###autoload (define-key menu-bar-bookmark-map [rename] - '("Rename bookmark" . bookmark-menu-rename)) + '("Rename Bookmark" . bookmark-menu-rename)) +;;;###autoload (define-key menu-bar-bookmark-map [locate] - '("Insert location" . bookmark-menu-locate)) + '("Insert Location" . bookmark-menu-locate)) +;;;###autoload (define-key menu-bar-bookmark-map [insert] - '("Insert contents" . bookmark-menu-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-jump)) - -;;;###autoload (autoload 'menu-bar-bookmark-map "bookmark" nil t 'keymap) - -(fset 'menu-bar-bookmark-map (symbol-value 'menu-bar-bookmark-map)) + '("Jump to Bookmark" . bookmark-menu-jump)) ;;;; end bookmark menu stuff ;;;;