From: Andreas Gerler Date: Fri, 11 Feb 2022 15:55:16 +0000 (+0100) Subject: add Bookmark plus X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=dc0006d3cb24b1393b9572567e458d7238f31f92;p=emacsconfig.git add Bookmark plus Signed-off-by: Andreas Gerler --- diff --git a/bba.org b/bba.org index 7ed0726d..98fd3eb4 100644 --- a/bba.org +++ b/bba.org @@ -332,6 +332,23 @@ Keep track of your important stuff! (define-key calendar-mode-map (kbd "RET") 'calendar-insert-date) #+end_src + +* [[https://www.emacswiki.org/emacs/BookmarkPlus][Bookmark+]] +[2022-02-10 Thu 15:22] + +#+BEGIN_SRC emacs-lisp + (if (equal "work" (getenv "SYSENV")) + (setq bookmark-default-file "~/workorg/bookmarks") + (setq bookmark-default-file "~/org/bookmarks")) + (load-file (expand-file-name "~/.emacs.d/lisp/bookmark+.el")) + (load-file (expand-file-name "~/.emacs.d/lisp/bookmark+-mac.el")) + (load-file (expand-file-name "~/.emacs.d/lisp/bookmark+-bmu.el")) + (load-file (expand-file-name "~/.emacs.d/lisp/bookmark+-1.el")) + (load-file (expand-file-name "~/.emacs.d/lisp/bookmark+-key.el")) + (load-file (expand-file-name "~/.emacs.d/lisp/bookmark+-lit.el")) + +#+END_SRC + * magit For annotated tags prepare message with commit messages since last tag. diff --git a/lisp/bookmark+-1.el b/lisp/bookmark+-1.el new file mode 100644 index 00000000..e8ea6df9 --- /dev/null +++ b/lisp/bookmark+-1.el @@ -0,0 +1,13889 @@ +;;; bookmark+-1.el - First part of package Bookmark+. +;; +;; Filename: bookmark+-1.el +;; Description: First part of package Bookmark+. +;; Author: Drew Adams, Thierry Volpiatto +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2000-2022, Drew Adams, all rights reserved. +;; Copyright (C) 2009, Thierry Volpiatto. +;; Created: Mon Jul 12 13:43:55 2010 (-0700) +;; Last-Updated: Fri Jan 14 12:34:36 2022 (-0800) +;; By: dradams +;; Update #: 9453 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-1.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+, placeholders, annotations, search, info, url, eww, w3m, gnus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; `backquote', `bookmark', `bookmark+-1', `button', `bytecomp', +;; `cconv', `cl-lib', `col-highlight', `crosshairs', `font-lock', +;; `font-lock+', `help-mode', `hl-line', `hl-line+', `kmacro', +;; `macroexp', `pp', `replace', `syntax', `text-mode', `thingatpt', +;; `thingatpt+', `vline'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) library +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit.el' - (optional) code for highlighting bookmarks +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (bmenu) +;; `bookmark+-1.el' - other (non-bmenu) required code (this file) +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc.el' - documentation (comment-only file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you have library +;; `bookmark+-doc.el' in your `load-path'.) + +;;(@> "Index") +;; +;; Index +;; ----- +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "Things Defined Here") +;; (@> "User Options (Customizable)") +;; (@> "Internal Variables") +;; (@> "Compatibility Code for Older Emacs Versions") +;; (@> "Core Replacements (`bookmark-*' except `bookmark-bmenu-*')") +;; (@> "Bookmark+ Functions (`bmkp-*')") +;; (@> "Search-and-Replace Locations of Marked Bookmarks") +;; (@> "Tags") +;; (@> "Bookmark Predicates") +;; (@> "Filter Functions") +;; (@> "General Utility Functions") +;; (@> "Bookmark Entry Access Functions") +;; (@> "Sorting - General Functions") +;; (@> "Sorting - Commands") +;; (@> "Sorting - General Predicates") +;; (@> "Sorting - File-Name Predicates") +;; (@> "Indirect Bookmarking Functions") +;; (@> "Other Bookmark+ Functions (`bmkp-*')") +;; (@> "Keymaps") + +;;(@* "Things Defined Here") +;; +;; Things Defined Here +;; ------------------- +;; +;; Commands defined here: +;; +;; `bmkp-add-tags', `bmkp-all-tags-jump', +;; `bmkp-all-tags-jump-other-window', `bmkp-all-tags-regexp-jump', +;; `bmkp-all-tags-regexp-jump-other-window', +;; `bmkp-annotate-all-bookmarks-this-file/buffer', +;; `bmkp-annotate-bookmark', +;; `bmkp-annotate-bookmark-this-file/buffer', +;; `bmkp-autofile-add-tags', `bmkp-autofile-all-tags-jump', +;; `bmkp-autofile-all-tags-jump-other-window', +;; `bmkp-autofile-all-tags-regexp-jump', +;; `bmkp-autofile-all-tags-regexp-jump-other-window', +;; `bmkp-autofile-jump', `bmkp-autofile-jump-other-window', +;; `bmkp-autofile-remove-tags', `bmkp-autofile-set', +;; `bmkp-autofile-some-tags-jump', +;; `bmkp-autofile-some-tags-jump-other-window', +;; `bmkp-autofile-some-tags-regexp-jump', +;; `bmkp-autofile-some-tags-regexp-jump-other-window', +;; `bmkp-automatic-bookmark-mode', `bmkp-autonamed-jump', +;; `bmkp-autonamed-jump-other-window', +;; `bmkp-autonamed-this-buffer-jump', +;; `bmkp-autonamed-this-buffer-jump-other-window', +;; `bmkp-bookmark-a-file' `bmkp-bookmark-file-jump', +;; `bmkp-bookmark-file-load-jump', +;; `bmkp-bookmark-file-switch-jump', `bmkp-bookmark-linked-at' +;; (Emacs 22+), `bmkp-bookmark-linked-at-mouse' (Emacs 22+), +;; `bmkp-bookmark-list-jump', +;; `bmkp-bookmark-set-confirm-overwrite', +;; `bmkp-choose-navlist-from-bookmark-list', +;; `bmkp-choose-navlist-of-type', `bmkp-clone-bookmark', +;; `bmkp-compilation-target-set', +;; `bmkp-compilation-target-set-all', `bmkp-copy-bookmark', +;; `bmkp-convert-eww-bookmarks' (Emacs 25+), `bmkp-copy-tags', +;; `bmkp-crosshairs-highlight', `bmkp-cycle', +;; `bmkp-cycle-autonamed', `bmkp-cycle-autonamed-other-window', +;; `bmkp-cycle-bookmark-list', +;; `bmkp-cycle-bookmark-list-other-window', `bmkp-cycle-desktop', +;; `bmkp-cycle-dired', `bmkp-cycle-dired-other-window', +;; `bmkp-cycle-eww', `bmkp-cycle-eww-other-window', +;; `bmkp-cycle-file', `bmkp-cycle-file-other-window', +;; `bmkp-cycle-gnus', `bmkp-cycle-gnus-other-window', +;; `bmkp-cycle-info', `bmkp-cycle-info-other-window', +;; `bmkp-cycle-lighted', `bmkp-cycle-lighted-other-window', +;; `bmkp-cycle-local-file', `bmkp-cycle-local-file-other-window', +;; `bmkp-cycle-man', `bmkp-cycle-man-other-window', +;; `bmkp-cycle-non-file', `bmkp-cycle-non-file-other-window', +;; `bmkp-cycle-other-window', `bmkp-cycle-remote-file', +;; `bmkp-cycle-remote-file-other-window', +;; `bmkp-cycle-specific-buffers', +;; `bmkp-cycle-specific-buffers-other-window', +;; `bmkp-cycle-specific-files', +;; `bmkp-cycle-specific-files-other-window', +;; `bmkp-cycle-this-buffer', `bmkp-cycle-this-buffer-other-window', +;; `bmkp-cycle-this-file', `bmkp-cycle-this-file/buffer', +;; `bmkp-cycle-this-file/buffer-other-window', +;; `bmkp-cycle-this-file-other-window', `bmkp-cycle-variable-list', +;; `bmkp-cycle-url', `bmkp-cycle-url-other-window', +;; `bmkp-delete-all-autonamed-for-this-buffer', +;; `bmkp-delete-all-temporary-bookmarks', `bmkp-delete-bookmarks', +;; `bmkp-describe-bookmark', `bmkp-describe-bookmark-internals', +;; `bmkp-desktop-change-dir', `bmkp-desktop-delete', +;; `bmkp-desktop-jump', `bmkp-desktop-read', `bmkp-dired-jump', +;; `bmkp-dired-jump-other-window', `bmkp-dired-this-dir-jump', +;; `bmkp-dired-this-dir-jump-other-window', +;; `bmkp-edit-bookmark-name-and-location', +;; `bmkp-edit-bookmark-record', +;; `bmkp-edit-bookmark-record-file/buffer', +;; `bmkp-edit-bookmark-record-send', +;; `bmkp-edit-bookmark-records-send', `bmkp-edit-tags', +;; `bmkp-edit-tags-send', `bmkp-edit-this-annotation', +;; `bmkp-empty-file', `bmkp-eww-jump' (Emacs 25+), +;; `bmkp-eww-jump-other-window' (Emacs 25+), +;; `bmkp-eww-auto-bookmark-mode' (Emacs 25+), +;; `bmkp-ffap-max-region-size', `bmkp-file-target-set', +;; `bmkp-file-all-tags-jump', +;; `bmkp-file-all-tags-jump-other-window', +;; `bmkp-file-all-tags-regexp-jump', +;; `bmkp-file-all-tags-regexp-jump-other-window', `bmkp-file-jump', +;; `bmkp-file-jump-other-window', `bmkp-file-some-tags-jump', +;; `bmkp-file-some-tags-jump-other-window', +;; `bmkp-file-some-tags-regexp-jump', +;; `bmkp-file-some-tags-regexp-jump-other-window', +;; `bmkp-file-this-dir-all-tags-jump', +;; `bmkp-file-this-dir-all-tags-jump-other-window', +;; `bmkp-file-this-dir-all-tags-regexp-jump', +;; `bmkp-file-this-dir-all-tags-regexp-jump-other-window', +;; `bmkp-file-this-dir-jump', +;; `bmkp-file-this-dir-jump-other-window', +;; `bmkp-file-this-dir-some-tags-jump', +;; `bmkp-file-this-dir-some-tags-jump-other-window', +;; `bmkp-file-this-dir-some-tags-regexp-jump', +;; `bmkp-file-this-dir-some-tags-regexp-jump-other-window', +;; `bmkp-find-file', `bmkp-find-file-other-window', +;; `bmkp-find-file-all-tags', +;; `bmkp-find-file-all-tags-other-window', +;; `bmkp-find-file-all-tags-regexp', +;; `bmkp-find-file-all-tags-regexp-other-window', +;; `bmkp-find-file-some-tags', +;; `bmkp-find-file-some-tags-other-window', +;; `bmkp-find-file-some-tags-regexp', +;; `bmkp-find-file-some-tags-regexp-other-window', +;; `bmkp-get-external-annotation', +;; `bmkp-global-automatic-bookmark-mode' (Emacs 21+), +;; `bmkp-gnus-jump', `bmkp-gnus-jump-other-window', +;; `bmkp-image-jump', `bmkp-image-jump-other-window', +;; `bmkp-info-auto-bookmark-mode' (Emacs 22+), `bmkp-info-jump', +;; `bmkp-info-jump-other-window', `bmkp-insert-bookmark-link' +;; (Emacs 22+), `bmkp-jump-in-navlist', +;; `bmkp-jump-in-navlist-other-window', +;; `bmkp-jump-to-bookmark-linked-at' (Emacs 22+), +;; `bmkp-jump-to-bookmark-linked-at-mouse' (Emacs 22+), +;; `bmkp-jump-to-list', `bmkp-jump-to-type', +;; `bmkp-jump-to-type-other-window', `bmkp-list-all-tags', +;; `bmkp-list-defuns-in-commands-file', `bmkp-local-file-jump', +;; `bmkp-local-file-jump-other-window', +;; `bmkp-local-non-dir-file-jump', +;; `bmkp-local-non-dir-file-jump-other-window', +;; `bmkp-make-bookmark-savable', `bmkp-make-bookmark-temporary', +;; `bmkp-make-function-bookmark', `bmkp-man-jump', +;; `bmkp-man-jump-other-window', `bmkp-menu-jump-other-window' +;; (Emacs 20, 21), `bmkp-navlist-bmenu-list', +;; `bmkp-next-autonamed-bookmark', +;; `bmkp-next-autonamed-bookmark-other-window', +;; `bmkp-next-autonamed-bookmark-other-window-repeat', +;; `bmkp-next-autonamed-bookmark-repeat', `bmkp-next-bookmark', +;; `bmkp-next-bookmark-list-bookmark', +;; `bmkp-next-bookmark-list-bookmark-other-window', +;; `bmkp-next-bookmark-list-bookmark-other-window-repeat', +;; `bmkp-next-bookmark-list-bookmark-repeat', +;; `bmkp-next-bookmark-other-window', +;; `bmkp-next-bookmark-other-window-repeat', +;; `bmkp-next-bookmark-repeat', `bmkp-next-bookmark-this-buffer', +;; `bmkp-next-bookmark-this-buffer-other-window', +;; `bmkp-next-bookmark-this-buffer-other-window-repeat', +;; `bmkp-next-bookmark-this-buffer-repeat', +;; `bmkp-next-bookmark-this-file', +;; `bmkp-next-bookmark-this-file/buffer', +;; `bmkp-next-bookmark-this-file/buffer-other-window', +;; `bmkp-next-bookmark-this-file/buffer-other-window-repeat', +;; `bmkp-next-bookmark-this-file/buffer-repeat', +;; `bmkp-next-bookmark-this-file-other-window', +;; `bmkp-next-bookmark-this-file-other-window-repeat', +;; `bmkp-next-bookmark-this-file-repeat', +;; `bmkp-next-desktop-bookmark', +;; `bmkp-next-desktop-bookmark-other-window', +;; `bmkp-next-desktop-bookmark-other-window-repeat', +;; `bmkp-next-desktop-bookmark-repeat', `bmkp-next-dired-bookmark', +;; `bmkp-next-dired-bookmark-other-window', +;; `bmkp-next-dired-bookmark-other-window-repeat', +;; `bmkp-next-dired-bookmark-repeat', `bmkp-next-eww-bookmark', +;; `bmkp-next-eww-bookmark-other-window', +;; `bmkp-next-eww-bookmark-other-window-repeat', +;; `bmkp-next-eww-bookmark-repeat', `bmkp-next-file-bookmark', +;; `bmkp-next-file-bookmark-other-window', +;; `bmkp-next-file-bookmark-other-window-repeat', +;; `bmkp-next-file-bookmark-repeat', `bmkp-next-gnus-bookmark', +;; `bmkp-next-gnus-bookmark-other-window', +;; `bmkp-next-gnus-bookmark-other-window-repeat', +;; `bmkp-next-gnus-bookmark-repeat', `bmkp-next-info-bookmark', +;; `bmkp-next-info-bookmark-other-window', +;; `bmkp-next-info-bookmark-other-window-repeat', +;; `bmkp-next-info-bookmark-repeat', `bmkp-next-lighted-bookmark', +;; `bmkp-next-lighted-bookmark-other-window', +;; `bmkp-next-lighted-bookmark-other-window-repeat', +;; `bmkp-next-lighted-bookmark-repeat', +;; `bmkp-next-local-file-bookmark', +;; `bmkp-next-local-file-bookmark-other-window', +;; `bmkp-next-local-file-bookmark-other-window-repeat', +;; `bmkp-next-local-file-bookmark-repeat', +;; `bmkp-next-man-bookmark', `bmkp-next-man-bookmark-other-window', +;; `bmkp-next-man-bookmark-other-window-repeat', +;; `bmkp-next-man-bookmark-repeat', `bmkp-next-non-file-bookmark', +;; `bmkp-next-non-file-bookmark-other-window', +;; `bmkp-next-non-file-bookmark-other-window-repeat', +;; `bmkp-next-non-file-bookmark-repeat', +;; `bmkp-next-remote-file-bookmark', +;; `bmkp-next-remote-file-bookmark-other-window', +;; `bmkp-next-remote-file-bookmark-other-window-repeat', +;; `bmkp-next-remote-file-bookmark-repeat', +;; `bmkp-next-specific-buffers-bookmark', +;; `bmkp-next-specific-buffers-bookmark-other-window', +;; `bmkp-next-specific-buffers-bookmark-other-window-repeat', +;; `bmkp-next-specific-buffers-bookmark-repeat', +;; `bmkp-next-specific-files-bookmark', +;; `bmkp-next-specific-files-bookmark-other-window', +;; `bmkp-next-specific-files-bookmark-other-window-repeat', +;; `bmkp-next-specific-files-bookmark-repeat', +;; `bmkp-next-variable-list-bookmark', +;; `bmkp-next-variable-list-bookmark-other-window', +;; `bmkp-next-variable-list-bookmark-other-window-repeat', +;; `bmkp-next-variable-list-bookmark-repeat', +;; `bmkp-next-url-bookmark', `bmkp-next-url-bookmark-other-window', +;; `bmkp-next-url-bookmark-other-window-repeat', +;; `bmkp-next-url-bookmark-repeat', `bmkp-next-bookmark-w32', +;; `bmkp-next-bookmark-w32-other-window', +;; `bmkp-next-bookmark-w32-other-window-repeat', +;; `bmkp-next-bookmark-w32-repeat', `bmkp-non-dir-file-jump', +;; `bmkp-non-dir-file-jump-other-window', `bmkp-non-file-jump', +;; `bmkp-non-file-jump-other-window', +;; `bmkp-occur-create-autonamed-bookmarks', +;; `bmkp-ORIG-bookmark-insert', `bmkp-occur-target-set', +;; `bmkp-occur-target-set-all', `bmkp-paste-add-tags', +;; `bmkp-paste-replace-tags', `bmkp-previous-autonamed-bookmark', +;; `bmkp-previous-autonamed-bookmark-other-window', +;; `bmkp-previous-autonamed-bookmark-other-window-repeat', +;; `bmkp-previous-autonamed-bookmark-repeat', +;; `bmkp-previous-bookmark', +;; `bmkp-previous-bookmark-list-bookmark', +;; `bmkp-previous-bookmark-list-bookmark-other-window', +;; `bmkp-previous-bookmark-list-bookmark-other-window-repeat', +;; `bmkp-previous-bookmark-list-bookmark-repeat', +;; `bmkp-previous-bookmark-list-repeat', +;; `bmkp-previous-bookmark-other-window', +;; `bmkp-previous-bookmark-other-window-repeat', +;; `bmkp-previous-bookmark-repeat', +;; `bmkp-previous-bookmark-this-buffer', +;; `bmkp-previous-bookmark-this-buffer-other-window', +;; `bmkp-previous-bookmark-this-buffer-other-window-repeat', +;; `bmkp-previous-bookmark-this-buffer-repeat', +;; `bmkp-previous-bookmark-this-file', +;; `bmkp-previous-bookmark-this-file/buffer', +;; `bmkp-previous-bookmark-this-file/buffer-other-window', +;; `bmkp-previous-bookmark-this-file/buffer-other-window-repeat', +;; `bmkp-previous-bookmark-this-file/buffer-repeat', +;; `bmkp-previous-bookmark-this-file-other-window', +;; `bmkp-previous-bookmark-this-file-other-window-repeat', +;; `bmkp-previous-bookmark-this-file-repeat', +;; `bmkp-previous-desktop-bookmark', +;; `bmkp-previous-desktop-bookmark-other-window', +;; `bmkp-previous-desktop-bookmark-other-window-repeat', +;; `bmkp-previous-desktop-bookmark-repeat', +;; `bmkp-previous-dired-bookmark', +;; `bmkp-previous-dired-bookmark-other-window', +;; `bmkp-previous-dired-bookmark-other-window-repeat', +;; `bmkp-previous-dired-bookmark-repeat', +;; `bmkp-previous-eww-bookmark', +;; `bmkp-previous-eww-bookmark-other-window', +;; `bmkp-previous-eww-bookmark-other-window-repeat', +;; `bmkp-previous-eww-bookmark-repeat', +;; `bmkp-previous-file-bookmark', +;; `bmkp-previous-file-bookmark-other-window', +;; `bmkp-previous-file-bookmark-other-window-repeat', +;; `bmkp-previous-file-bookmark-repeat', +;; `bmkp-previous-gnus-bookmark', +;; `bmkp-previous-gnus-bookmark-other-window', +;; `bmkp-previous-gnus-bookmark-other-window-repeat', +;; `bmkp-previous-gnus-bookmark-repeat', +;; `bmkp-previous-info-bookmark', +;; `bmkp-previous-info-bookmark-other-window', +;; `bmkp-previous-info-bookmark-other-window-repeat', +;; `bmkp-previous-info-bookmark-repeat', +;; `bmkp-previous-lighted-bookmark', +;; `bmkp-previous-lighted-bookmark-other-window', +;; `bmkp-previous-lighted-bookmark-other-window-repeat', +;; `bmkp-previous-lighted-bookmark-repeat', +;; `bmkp-previous-local-file-bookmark', +;; `bmkp-previous-local-file-bookmark-other-window', +;; `bmkp-previous-local-file-bookmark-other-window-repeat', +;; `bmkp-previous-local-file-bookmark-repeat', +;; `bmkp-previous-man-bookmark', +;; `bmkp-previous-man-bookmark-other-window', +;; `bmkp-previous-man-bookmark-other-window-repeat', +;; `bmkp-previous-man-bookmark-repeat', +;; `bmkp-previous-non-file-bookmark', +;; `bmkp-previous-non-file-bookmark-other-window', +;; `bmkp-previous-non-file-bookmark-other-window-repeat', +;; `bmkp-previous-non-file-bookmark-repeat', +;; `bmkp-previous-remote-file-bookmark', +;; `bmkp-previous-remote-file-bookmark-other-window', +;; `bmkp-previous-remote-file-bookmark-other-window-repeat', +;; `bmkp-previous-remote-file-bookmark-repeat', +;; `bmkp-previous-specific-buffers-bookmark', +;; `bmkp-previous-specific-buffers-bookmark-other-window', +;; `bmkp-previous-specific-buffers-bookmark-other-window-repeat', +;; `bmkp-previous-specific-buffers-bookmark-repeat', +;; `bmkp-previous-specific-files-bookmark', +;; `bmkp-previous-specific-files-bookmark-other-window', +;; `bmkp-previous-specific-files-bookmark-other-window-repeat', +;; `bmkp-previous-specific-files-bookmark-repeat', +;; `bmkp-previous-variable-list-bookmark', +;; `bmkp-previous-variable-list-bookmark-other-window', +;; `bmkp-previous-variable-list-bookmark-other-window-repeat', +;; `bmkp-previous-variable-list-bookmark-repeat', +;; `bmkp-previous-url-bookmark', +;; `bmkp-previous-url-bookmark-other-window', +;; `bmkp-previous-url-bookmark-other-window-repeat', +;; `bmkp-previous-url-bookmark-repeat', +;; `bmkp-previous-bookmark-w32', +;; `bmkp-previous-bookmark-w32-other-window', +;; `bmkp-previous-bookmark-w32-other-window-repeat', +;; `bmkp-previous-bookmark-w32-repeat', +;; `bmkp-purge-notags-autofiles', `bmkp-read-bookmark-for-type', +;; `bmkp-region-jump', +;; `bmkp-region-jump-narrow-indirect-other-window', +;; `bmkp-region-jump-other-window', `bmkp-remote-file-jump', +;; `bmkp-remote-file-jump-other-window', +;; `bmkp-remote-non-dir-file-jump', +;; `bmkp-temote-non-dir-file-jump-other-window', +;; `bmkp-remove-all-tags', `bmkp-remove-tags', +;; `bmkp-remove-tags-from-all', `bmkp-rename-tag', +;; `bmkp-retrieve-icicle-search-hits', +;; `bmkp-retrieve-more-icicle-search-hits', +;; `bmkp-revert-bookmark-file', +;; `bmkp-save-bookmarks-this-file/buffer', +;; `bmkp-save-menu-list-state', `bmkp-send-bug-report', +;; `bmkp-set-autonamed-bookmark', +;; `bmkp-set-autonamed-bookmark-at-line', +;; `bmkp-set-autonamed-regexp-buffer', +;; `bmkp-set-autonamed-regexp-region', +;; `bmkp-set-bookmark-file-bookmark', `bmkp-set-desktop-bookmark', +;; `bmkp-set-dired-bookmark-for-files', +;; `bmkp-set-eww-bookmark-here' (Emacs 25+), +;; `bmkp-set-grep-command-bookmark' (Emacs 26+), +;; `bmkp-set-icicle-search-hits-bookmark', +;; `bmkp-set-info-bookmark-with-node-name' (Emacs 22+), +;; `bmkp-set-izones-bookmark', `bmkp-set-kmacro-bookmark' (Emacs +;; 22+), `bmkp-set-kmacro-list-bookmark' (Emacs 22+), +;; `bmkp-set-sequence-bookmark', `bmkp-set-snippet-bookmark', +;; `bmkp-set-tag-value', `bmkp-set-tag-value-for-navlist', +;; `bmkp-set-variable-list-bookmark', +;; `bmkp-show-this-annotation-read-only', +;; `bmkp-snippet-to-kill-ring', `bmkp-some-tags-jump', +;; `bmkp-some-tags-jump-other-window', +;; `bmkp-some-tags-regexp-jump', +;; `bmkp-some-tags-regexp-jump-other-window', +;; `bmkp-specific-buffers-jump', +;; `bmkp-specific-buffers-jump-other-window', +;; `bmkp-specific-files-jump', +;; `bmkp-specific-files-jump-other-window', `bmkp-store-org-link' +;; (Emacs 24.4+), `bmkp-switch-bookmark-file', +;; `bmkp-switch-bookmark-file-create', +;; `bmkp-switch-to-bookmark-file-this-file/buffer', +;; `bmkp-switch-to-last-bookmark-file', `bmkp-tag-a-file', +;; `bmkp-temporary-bookmarking-mode', `bmkp-temporary-jump', +;; `bmkp-temporary-jump-other-window', +;; `bmkp-this-buffer-bmenu-list', `bmkp-this-buffer-jump', +;; `bmkp-this-buffer-jump-other-window', +;; `bmkp-this-file-bmenu-list', `bmkp-this-file/buffer-bmenu-list', +;; `bmkp-toggle-autonamed-bookmark-set/delete', +;; `bmkp-toggle-autotemp-on-set', +;; `bmkp-toggle-bookmark-set-refreshes', +;; `bmkp-toggle-eww-auto-type' (Emacs 25+), +;; `bmkp-toggle-info-auto-type' (Emacs 22+), +;; `bmkp-toggle-saving-bookmark-file', +;; `bmkp-toggle-saving-menu-list-state', +;; `bmkp-toggle-temporary-bookmark', +;; `bmkp-turn-on-automatic-bookmark-mode' (Emacs 21+), +;; `bmkp-types-alist', `bmkp-unomit-all', `bmkp-untag-a-file', +;; `bmkp-url-target-set', `bmkp-url-jump', +;; `bmkp-url-jump-other-window', `bmkp-variable-list-jump', +;; `bmkp-version', `bmkp-visit-external-annotation', +;; `bmkp-w32-browser-jump', `bmkp-w3m-jump', +;; `bmkp-w3m-jump-other-window', +;; `bmkp-wrap-bookmark-with-last-kbd-macro'. +;; +;; User options defined here: +;; +;; `bmkp-annotation-modes-inherit-from', `bmkp-autofile-filecache', +;; `bmkp-automatic-bookmark-min-distance', +;; `bmkp-automatic-bookmark-mode-delay', +;; `bmkp-automatic-bookmark-mode-lighter', +;; `bmkp-automatic-bookmark-set-function', +;; `bmkp-autoname-bookmark-function', `bmkp-autoname-format', +;; `bmkp-autotemp-bookmark-predicates', +;; `bmkp-bookmark-name-length-max', +;; `bmkp-count-multi-mods-as-one-flag', `bmkp-crosshairs-flag', +;; `bmkp-default-bookmark-name', +;; `bmkp-default-handlers-for-file-types', +;; `bmkp-desktop-default-directory', +;; `bmkp-desktop-jump-save-before-flag', +;; `bmkp-desktop-no-save-vars', `bmkp-eww-auto-type' (Emacs 25+), +;; `bmkp-eww-buffer-renaming' (Emacs 25+), +;; `bmkp-eww-generate-buffer-flag' (Emacs 25+), +;; `bmkp-eww-replace-keys-flag' (Emacs 25+), +;; `bmkp-guess-default-handler-for-file-flag', +;; `bmkp-handle-region-function', `bmkp-incremental-filter-delay', +;; `bmkp-info-auto-type' (Emacs 22+), +;; `bmkp-info-sort-ignores-directories-flag', +;; `bmkp-last-as-first-bookmark-file', +;; `bmkp-menu-popup-max-length', `bmkp-new-bookmark-default-names', +;; `bmkp-other-window-pop-to-flag', `bmkp-prompt-for-tags-flag', +;; `bmkp-properties-to-keep', `bmkp-read-bookmark-file-hook', +;; `bmkp-region-search-size', `bmkp-save-new-location-flag', +;; `bmkp-sequence-jump-display-function', +;; `bmkp-show-end-of-region-flag', `bmkp-sort-comparer', +;; `bmkp-su-or-sudo-regexp', `bmkp-tags-for-completion', +;; `bmkp-temporary-bookmarking-mode', +;; `bmkp-temporary-bookmarking-mode-hook', +;; `bmkp-temporary-bookmarking-mode-lighter', +;; `bmkp-this-file/buffer-cycle-sort-comparer', `bmkp-use-region', +;; `bmkp-w3m-allow-multiple-buffers-flag', +;; `bmkp-write-bookmark-file-hook'. +;; +;; Non-interactive functions defined here: +;; +;; `bmkext-jump-gnus', `bmkext-jump-man', `bmkext-jump-w3m', +;; `bmkext-jump-woman', `bmkp-add-jump-to-list-button', +;; `bmkp-all-exif-data', `bmkp-all-tags-alist-only', +;; `bmkp-all-tags-regexp-alist-only', `bmkp-alpha-cp', +;; `bmkp-alpha-p', `bmkp-annotated-alist-only', +;; `bmkp-annotated-bookmark-p', `bmkp-annotated-cp', +;; `bmkp-annotation-or-bookmark-description', +;; `bmkp-autofile-alist-only', `bmkp-autofile-all-tags-alist-only', +;; `bmkp-autofile-all-tags-regexp-alist-only', +;; `bmkp-autofile-bookmark-p', +;; `bmkp-autofile-some-tags-alist-only', +;; `bmkp-autofile-some-tags-regexp-alist-only', +;; `bmkp-autoname-bookmark-function-default', +;; `bmkp-autonamed-alist-only', +;; `bmkp-autonamed-bookmark-for-buffer-p', +;; `bmkp-autonamed-bookmark-p', +;; `bmkp-autonamed-this-buffer-alist-only', +;; `bmkp-autonamed-this-buffer-bookmark-p', +;; `bmkp-bookmark-creation-cp', `bmkp-bookmark-data-from-record', +;; `bmkp-bookmark-description', `bmkp-bookmark-last-access-cp', +;; `bmkp-bookmark-file-alist-only', +;; `bmkp-bookmark-file-bookmark-p', +;; `bmkp-bookmark-list-alist-only', +;; `bmkp-bookmark-list-bookmark-p', `bmkp-bookmark-name-member', +;; `bmkp-bookmark-record-from-name', `bmkp-buffer-alist-only', +;; `bmkp-buffer-last-access-cp', `bmkp-buffer-names', +;; `bmkp-compilation-file+line-at', `bmkp-completing-read-1', +;; `bmkp-completing-read-bookmarks', +;; `bmkp-completing-read-buffer-name', +;; `bmkp-completing-read-file-name', `bmkp-completing-read-lax', +;; `bmkp-cp-not', `bmkp-create-variable-list-bookmark', +;; `bmkp-current-bookmark-list-state', `bmkp-current-sort-order', +;; `bmkp-cycle-1', `bmkp-default-bookmark-file', +;; `bmkp-default-bookmark-name', `bmkp-default-handler-for-file', +;; `bmkp-default-handler-user', `bmkp-delete-autonamed-no-confirm', +;; `bmkp-delete-autonamed-this-buffer-no-confirm', +;; `bmkp-delete-bookmark-name-from-list', +;; `bmkp-delete-temporary-no-confirm', `bmkp-desktop-alist-only', +;; `bmkp-desktop-bookmark-p', +;; `bmkp-desktop-file-p',`bmkp-desktop-kill', `bmkp-desktop-save', +;; `bmkp-desktop-save-as-last', `bmkp-dired-alist-only', +;; `bmkp-dired-bookmark-p', `bmkp-dired-remember-*-marks', +;; `bmkp-dired-subdirs', `bmkp-dired-this-dir-alist-only', +;; `bmkp-dired-wildcards-alist-only', +;; `bmkp-dired-this-dir-bookmark-p', +;; `bmkp-dired-wildcards-bookmark-p', +;; `bmkp-edit-bookmark-record-mode', +;; `bmkp-edit-bookmark-records-mode', `bmkp-edit-tags-mode', +;; `bmkp-end-position-post-context', +;; `bmkp-end-position-pre-context', `bmkp-every', +;; `bmkp-eww-alist-only' (Emacs 25+), `bmkp-eww-bookmark-p' (Emacs +;; 25+), `bmkp-eww-cp' (Emacs 25+), `bmkp-eww-new-buffer-name' +;; (Emacs 25+), `bmkp-eww-rename-buffer' (Emacs 25+), +;; `bmkp-eww-title' (Emacs 25+), `bmkp-eww-url' (Emacs 25+), +;; `bmkp-ffap-guesser', `bmkp-file-alist-only', +;; `bmkp-file-all-tags-alist-only', +;; `bmkp-file-all-tags-regexp-alist-only', `bmkp-file-alpha-cp', +;; `bmkp-file-attribute-0-cp', `bmkp-file-attribute-1-cp', +;; `bmkp-file-attribute-2-cp', `bmkp-file-attribute-3-cp', +;; `bmkp-file-attribute-4-cp', `bmkp-file-attribute-5-cp', +;; `bmkp-file-attribute-6-cp', `bmkp-file-attribute-7-cp', +;; `bmkp-file-attribute-8-cp', `bmkp-file-attribute-9-cp', +;; `bmkp-file-attribute-10-cp', `bmkp-file-attribute-11-cp', +;; `bmkp-file-bookmark-p', `bmkp-file-names', `bmkp-file-remote-p', +;; `bmkp-file-some-tags-alist-only', +;; `bmkp-file-some-tags-regexp-alist-only', +;; `bmkp-file-this-dir-alist-only', +;; `bmkp-file-this-dir-all-tags-alist-only', +;; `bmkp-file-this-dir-all-tags-regexp-alist-only', +;; `bmkp-file-this-dir-bookmark-p', +;; `bmkp-file-this-dir-some-tags-alist-only', +;; `bmkp-file-this-dir-some-tags-regexp-alist-only', +;; `bmkp-find-tag-default-as-regexp' (Emacs 22-24.2), +;; `bmkp-flagged-bookmark-p', `bmkp-flagged-cp', `bmkp-float-time', +;; `bmkp-format-spec', `bmkp-full-tag', `bmkp-function-alist-only', +;; `bmkp-function-bookmark-p', `bmkp-get-autofile-bookmark', +;; `bmkp-get-bookmark', `bmkp-get-bookmark-in-alist', +;; `bmkp-get-buffer-name', `bmkp-get-end-position', +;; `bmkp-get-tag-value', `bmkp-get-tags', `bmkp-get-visit-time', +;; `bmkp-get-visits-count', `bmkp-gnus-alist-only', +;; `bmkp-gnus-bookmark-p', `bmkp-gnus-cp', `bmkp-goto-position', +;; `bmkp-handle-region-default', +;; `bmkp-handle-region+narrow-indirect', `bmkp-handler-cp', +;; `bmkp-handler-pred', `bmkp-has-tag-p', +;; `bmkp-icicles-search-hits-alist-only', +;; `bmkp-icicles-search-hits-bookmark-p', `bmkp-image-alist-only', +;; `bmkp-image-bookmark-p', `bmkp-info-alist-only', +;; `bmkp-info-bookmark-p', `bmkp-info-node-name-cp', +;; `bmkp-info-position-cp', `bmkp-isearch-bookmarks' (Emacs 23+), +;; `bmkp-isearch-bookmarks-regexp' (Emacs 23+), +;; `bmkp-isearch-next-bookmark-buffer' (Emacs 23+), `bmkp-jump-1', +;; `bmkp-jump-bookmark-file', `bmkp-jump-bookmark-list', +;; `bmkp-jump-desktop', `bmkp-jump-dired', `bmkp-jump-eww' (Emacs +;; 25+), `bmkp-jump-function', `bmkp-jump-gnus', +;; `bmkp-jump-icicle-search-hits', `bmkp-jump-kmacro-list' (Emacs +;; 22+), `bmkp-jump-man', `bmkp-jump-sequence', +;; `bmkp-jump-snippet', `bmkp-jump-url-browse', +;; `bmkp-jump-variable-list', `bmkp-jump-w3m', +;; `bmkp-jump-w3m-new-buffer', `bmkp-jump-w3m-new-buffer', +;; `bmkp-jump-w3m-only-one-buffer', +;; `bmkp-jump-w3m-only-one-buffer', `bmkp-jump-woman', +;; `bmkp-kmacro-list-bookmark-p', +;; `bmkp-last-specific-buffer-alist-only', +;; `bmkp-last-specific-buffer-p', +;; `bmkp-last-specific-file-alist-only', +;; `bmkp-last-specific-file-p', `bmkp-list-position', +;; `bmkp-local-directory-bookmark-p', +;; `bmkp-local-file-accessed-more-recently-cp', +;; `bmkp-local-file-alist-only', `bmkp-local-file-bookmark-p', +;; `bmkp-local-file-size-cp', `bmkp-local-file-type-cp', +;; `bmkp-local-non-dir-file-alist-only', +;; `bmkp-local-non-dir-file-bookmark-p', +;; `bmkp-local-file-updated-more-recently-cp', +;; `bmkp-make-bookmark-file-record', +;; `bmkp-make-bookmark-list-record', `bmkp-make-desktop-record', +;; `bmkp-make-dired-record', `bmkp-make-eww-record' (Emacs 25+), +;; `bmkp-make-gnus-record', `bmkp-make-icicle-search-hits-record', +;; `bmkp-make-kmacro-list-record' (Emacs 22+), +;; `bmkp-make-man-record', `bmkp-make-obsolete', +;; `bmkp-make-obsolete-variable', `bmkp-make-plain-predicate', +;; `bmkp-make-record-for-target-file', `bmkp-make-sequence-record', +;; `bmkp-make-url-browse-record', `bmkp-make-variable-list-record', +;; `bmkp-make-w3m-record', `bmkp-make-woman-record' (Emacs 21+), +;; `bmkp-man-alist-only', `bmkp-man-bookmark-p', +;; `bmkp-marked-bookmark-p', `bmkp-marked-bookmarks-only', +;; `bmkp-marked-cp', `bmkp-maybe-save-bookmarks', +;; `bmkp-modified-bookmark-p', `bmkp-modified-cp', +;; `bmkp-msg-about-sort-order', `bmkp-multi-sort', +;; `bmkp-names-same-bookmark-p', `bmkp-navlist-bookmark-p', +;; `bmkp-new-bookmark-default-names', +;; `bmkp-non-autonamed-alist-only', `bmkp-non-dir-file-alist-only', +;; `bmkp-non-dir-file-bookmark-p', `bmkp-non-file-alist-only', +;; `bmkp-non-file-bookmark-p', `bmkp-non-invokable-alist-only', +;; `bmkp-non-invokable-bookmark-p', +;; `bmkp-not-near-other-automatic-bmks', `bmkp-omitted-alist-only', +;; `bmkp-orphaned-file-alist-only', +;; `bmkp-orphaned-file-bookmark-p', +;; `bmkp-orphaned-local-file-alist-only', +;; `bmkp-orphaned-local-file-bookmark-p', +;; `bmkp-orphaned-remote-file-alist-only', +;; `bmkp-orphaned-remote-file-bookmark-p', +;; `bmkp-pop-to-readable-marker', `bmkp-position-after-whitespace', +;; `bmkp-position-before-whitespace', `bmkp-position-cp', +;; `bmkp-position-post-context', +;; `bmkp-position-post-context-region', +;; `bmkp-position-pre-context', `bmkp-position-pre-context-region', +;; `bmkp-printable-vars+vals', `bmkp-propertize', +;; `bmkp-readable-p', `bmkp-read-bookmark-file-default', +;; `bmkp-read-bookmark-file-name', `bmkp-read-buffers', +;; `bmkp-read-files', `bmkp-read-from-whole-string', +;; `bmkp-read-regexp', `bmkp-read-tag-completing', +;; `bmkp-read-tags', `bmkp-read-tags-completing', +;; `bmkp-read-variable', `bmkp-read-variables-completing', +;; `bmkp-record-visit', `bmkp-refresh-latest-bookmark-list', +;; `bmkp-refresh-menu-list', `bmkp-refresh/rebuild-menu-list', +;; `bmkp-regexp-filtered-annotation-alist-only', +;; `bmkp-regexp-filtered-bookmark-name-alist-only', +;; `bmkp-regexp-filtered-file-name-alist-only', +;; `bmkp-regexp-filtered-tags-alist-only', +;; `bmkp-region-alist-only', `bmkp-region-bookmark-p', +;; `bmkp-remote-file-alist-only', `bmkp-remote-file-bookmark-p', +;; `bmkp-remote-non-dir-file-alist-only', +;; `bmkp-remote-non-dir-file-bookmark-p', `bmkp-remove-dups', +;; `bmkp-remove-if', `bmkp-remove-if-not', `bmkp-remove-omitted', +;; `bmkp-rename-for-marked-and-omitted-lists', +;; `bmkp-repeat-command', `bmkp-replace-existing-bookmark', +;; `bmkp-reset-bmkp-store-org-link-checking-p' (Emacs 24.4+), +;; `bmkp-retrieve-icicle-search-hits-1', +;; `bmkp-root-or-sudo-logged-p', `bmkp-same-creation-time-p', +;; `bmkp-same-file-p', `bmkp-save-new-region-location', +;; `bmkp-select-buffer-other-window', `bmkp-sequence-alist-only', +;; `bmkp-sequence-bookmark-p', `bmkp-set-automatic-bookmark', +;; `bmkp-set-tag-value-for-bookmarks', `bmkp-set-union', +;; `bmkp-snippet-alist-only', `bmkp-snippet-bookmark-p', +;; `bmkp-some', `bmkp-some-marked-p', `bmkp-some-tags-alist-only', +;; `bmkp-some-tags-regexp-alist-only', `bmkp-some-unmarked-p', +;; `bmkp-sorting-description', `bmkp-sort-omit', `bmkp-sound-jump', +;; `bmkp-specific-buffers-alist-only', +;; `bmkp-specific-files-alist-only', `bmkp-store-org-link-1', +;; `bmkp-string-less-case-fold-p', `bmkp-tagged-alist-only', +;; `bmkp-tagged-bookmark-p', `bmkp-tagged-cp', `bmkp-tag-name', +;; `bmkp-tags-in-bookmark-file', `bmkp-tags-list', +;; `bmkp-temporary-alist-only', `bmkp-temporary-bookmark-p', +;; `bmkp-thing-at-point', `bmkp-this-buffer-alist-only', +;; `bmkp-this-buffer-p', `bmkp-this-file-alist-only', +;; `bmkp-this-file/buffer-alist-only', `bmkp-this-file-p', +;; `bmkp-unmarked-bookmarks-only', `bmkp-unpropertized-string', +;; `bmkp-untagged-alist-only', `bmkp-upcase', +;; `bmkp-update-autonamed-bookmark', `bmkp-url-alist-only', +;; `bmkp-url-bookmark-p', `bmkp-url-browse-alist-only', +;; `bmkp-url-browse-bookmark-p', `bmkp-url-cp', +;; `bmkp-variable-list-alist-only', +;; `bmkp-variable-list-bookmark-p', `bmkp-visited-more-cp', +;; `bmkp-w3m-alist-only', `bmkp-w3m-bookmark-p', `bmkp-w3m-cp', +;; `bmkp-w3m-set-new-buffer-name', +;; `bmkp-write-alist-bookmarks-to-file'. +;; +;; Internal variables defined here: +;; +;; `bmkp-after-set-hook', `bmkp-autofile-history', +;; `bmkp-automatic-bookmark-mode-timer', +;; `bmkp-automatic-bookmarks', `bmkp-autonamed-history', +;; `bmkp-autotemp-all-when-set-p', `bmkp-before-jump-hook', +;; `bmkp-bookmark-file-history', `bmkp-bookmark-list-history', +;; `bmkp-bookmark-set-confirms-overwrite-p', +;; `bmkp-buffer-bookmark-p', `bmkp-current-bookmark-file', +;; `bmkp-current-nav-bookmark', `bmkp-desktop-current-file', +;; `bmkp-desktop-history', `bmkp-dired-history', +;; `bmkp-edit-bookmark-record-mode-map', +;; `bmkp-edit-bookmark-records-mode-map', +;; `bmkp-edit-bookmark-records-number', `bmkp-edit-tags-mode-map', +;; `bmkp-eww-history' (Emacs 25+), `bmkp-eww-jumping-p' (Emacs +;; 25+), `bmkp-eww-new-buf-name' (Emacs 25+), +;; `bmkp-file-bookmark-handlers', `bmkp-file-history', +;; `bmkp-gnus-history', `bmkp-icicles-search-hits-retrieve-more', +;; `bmkp-image-history', `bmkp-info-history', +;; `bmkp-isearch-bookmarks' (Emacs 23+), +;; `bmkp-jump-display-function', `bmkp-jump-other-window-map', +;; `bmkp-last-bmenu-state-file', `bmkp-last-bookmark-file', +;; `bmkp-last-save-flag-value', `bmkp-last-specific-buffer', +;; `bmkp-last-specific-file', `bmkp-latest-bookmark-alist', +;; `bmkp-local-file-history', `bmkp-man-history', +;; `bmkp-modified-bookmarks', `bmkp-nav-alist', +;; `bmkp-non-file-filename', `bmkp-non-file-history', +;; `bmkp-region-history', `bmkp-remote-file-history', +;; `bmkp-return-buffer', `bmkp-reverse-multi-sort-p', +;; `bmkp-reverse-sort-p', `bmkp-snippet-history', +;; `bmkp-sorted-alist', `bmkp-specific-buffers-history', +;; `bmkp-specific-files-history', `bmkp-store-org-link-checking-p', +;; `bmkp-tag-history', `bmkp-tags-alist', `bmkp-temporary-history', +;; `bmkp-url-history', `bmkp-use-w32-browser-p', +;; `bmkp-variable-list-history', `bmkp-version-number', +;; `bmkp-w3m-history'. +;; +;; +;; ***** NOTE: The following commands defined in `bookmark.el' +;; have been REDEFINED HERE: +;; +;; `bookmark-default-annotation-text', `bookmark-delete', +;; `bookmark-edit-annotation-mode', `bookmark-insert', +;; `bookmark-insert-annotation', +;; `bookmark-insert-current-bookmark', `bookmark-insert-location', +;; `bookmark-jump', `bookmark-jump-other-frame', +;; `bookmark-jump-other-window', `bookmark-load', +;; `bookmark-relocate', `bookmark-rename', `bookmark-save', +;; `bookmark-send-edited-annotation', `bookmark-set', +;; `bookmark-set-name', `bookmark-yank-word'. +;; +;; +;; ***** NOTE: The following user options defined in `bookmark.el' +;; have been REDEFINED HERE: +;; +;; `bookmark-automatically-show-annotations', `bookmark-sort-flag' +;; (document non-use), `bookmark-version-control'. +;; +;; +;; ***** NOTE: The following non-interactive functions defined in +;; `bookmark.el' have been REDEFINED HERE: +;; +;; `bookmark--jump-via', `bookmark-alist-from-buffer', +;; `bookmark-all-names', `bookmark-completing-read', +;; `bookmark-default-handler', `bookmark-edit-annotation' (command +;; here), `bookmark-exit-hook-internal', `bookmark-get-bookmark', +;; `bookmark-get-bookmark-record' (Emacs 20-22), +;; `bookmark-get-handler' (Emacs 20-22), +;; `bookmark-handle-bookmark', `bookmark-import-new-list', +;; `bookmark-jump-noselect' (Emacs 20-22), `bookmark-location', +;; `bookmark-make-record', `bookmark-make-record-default', +;; `bookmark-maybe-load-default-file', `bookmark-maybe-rename', +;; `bookmark-prop-get' (Emacs 20-22), `bookmark-prop-set', +;; `bookmark-show-annotation' (command here), +;; `bookmark-show-all-annotations' (command here), `bookmark-store' +;; (Emacs 20-22), `bookmark-write-file'. +;; +;; +;; ***** NOTE: The following internal variables defined in +;; `bookmark.el' have been REDEFINED HERE: +;; +;; `bookmark-alist' (doc string only), +;; `bookmark-make-record-function' (Emacs 20-22), +;; `bookmarks-already-loaded' (doc string only). +;; +;; +;; ***** NOTE: The following function defined in `info.el' +;; has been REDEFINED HERE: +;; +;; `Info-bookmark-make-record' (Emacs 20-22). +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;; + +(unless (fboundp 'file-remote-p) (require 'ffap)) ;; ffap-file-remote-p +(eval-when-compile (require 'gnus)) ;; mail-header-id (really in `nnheader.el') +(eval-when-compile (require 'gnus-sum)) ;; gnus-summary-article-header +(eval-when-compile (require 'cl)) ;; case, multiple-value-bind, typecase (plus, for Emacs 20: dolist, push) + +(when (and (require 'thingatpt+ nil t) ;; (no error if not found): + (fboundp 'tap-put-thing-at-point-props)) ; >= 2012-08-21 + (tap-define-aliases-wo-prefix) + (tap-put-thing-at-point-props)) +;; region-or-non-nil-symbol-name-nearest-point, symbol-nearest-point + +(when (> emacs-major-version 21) (require 'font-lock+ nil t)) ;; font-lock-ignore (text property) + +(require 'bookmark) +;; bookmark-alist, bookmark-alist-modification-count, bookmark-annotation-name, +;; bookmark-automatically-show-annotations, bookmark-bmenu-bookmark, +;; bookmark-bmenu-surreptitiously-rebuild-list, bookmark-buffer-file-name, bookmark-buffer-name, +;; bookmark-completion-ignore-case, bookmark-current-bookmark, bookmark-default-file, +;; bookmark-edit-annotation, bookmark-get-annotation, bookmark-get-bookmark, bookmark-get-bookmark-record, +;; bookmark-get-filename, bookmark-get-front-context-string, bookmark-get-handler, bookmark-get-position, +;; bookmark-get-rear-context-string, bookmark-insert-file-format-version-stamp, bookmark-kill-line, +;; bookmark-make-record, bookmark-maybe-historicize-string, bookmark-maybe-upgrade-file-format, +;; bookmark-menu-popup-paned-menu, bookmark-name-from-full-record, bookmark-name-from-record, +;; bookmark-popup-menu-and-apply-function, bookmark-prop-get, bookmark-save-flag, bookmark-search-size, +;; bookmark-set-annotation, bookmark-set-filename, bookmark-set-position, bookmark-time-to-save-p, +;; bookmark-use-annotations, bookmark-yank-point + + +;; Some general Renamings. +;; +;; 1. Fix incompatibility introduced by gratuitous Emacs name change. +;; +(cond ((and (fboundp 'bookmark-name-from-record) (not (fboundp 'bookmark-name-from-full-record))) + (defalias 'bookmark-name-from-full-record 'bookmark-name-from-record)) + ((and (fboundp 'bookmark-name-from-full-record) (not (fboundp 'bookmark-name-from-record))) + (defalias 'bookmark-name-from-record 'bookmark-name-from-full-record))) + +;; 2. The vanilla name of the first is misleading, as it returns only the cdr of the record. +;; The second is for consistency. +;; +(defalias 'bmkp-bookmark-data-from-record 'bookmark-get-bookmark-record) +(defalias 'bmkp-bookmark-name-from-record 'bookmark-name-from-full-record) + +;; 3. Do these up front. Emacs 23 made incompatible change to require all args. +;; +(defun bmkp-make-obsolete (obsolete-name current-name &optional when) + "Same as `make-obsolete', but usable also for Emacs prior to Emacs 23." + (if (< emacs-major-version 23) + (make-obsolete obsolete-name current-name) + (make-obsolete obsolete-name current-name when))) + +(defun bmkp-make-obsolete-variable (obsolete-name current-name &optional when access-type) + "Same as `make-obsolete-variable', but usable also for Emacs prior to Emacs 23." + (if (< emacs-major-version 23) + (make-obsolete-variable obsolete-name current-name) + (make-obsolete-variable obsolete-name current-name when))) + + + +(eval-when-compile + (or (condition-case nil + (load-library "bookmark+-mac") ; Use load-library to ensure latest .elc. + (error nil)) + (require 'bookmark+-mac))) ; Require, so can load separately if not on `load-path'. +;; bmkp-define-cycle-command, bmkp-define-file-sort-predicate, bmkp-define-next+prev-cycle-commands, +;; bmkp-with-help-window, bmkp-with-output-to-plain-temp-buffer + +(eval-when-compile (require 'bookmark+-bmu)) +;; bmkp-bmenu-before-hide-marked-alist, bmkp-bmenu-before-hide-unmarked-alist, bmkp-bmenu-commands-file, +;; bmkp-replace-regexp-in-string, bmkp-bmenu-filter-function, bmkp-bmenu-filter-pattern, +;; bmkp-bmenu-first-time-p, bmkp-flagged-bookmarks, bmkp-bmenu-goto-bookmark-named, +;; bmkp-bmenu-marked-bookmarks, bmkp-bmenu-omitted-bookmarks, bmkp-bmenu-refresh-menu-list, +;; bmkp-bmenu-show-all, bmkp-bmenu-state-file, bmkp-bmenu-title, bmkp-looking-at-p, +;; bmkp-maybe-unpropertize-bookmark-names, bmkp-sort-orders-alist, bookmark-bmenu-toggle-filenames + + +;; (eval-when-compile (require 'bookmark+-lit nil t)) +;; bmkp-light-bookmark, bmkp-light-bookmarks, bmkp-light-this-buffer + + +;; For the redefinition of `bookmark-get-bookmark'. +(provide 'bookmark+-1) ; Ensure this library is loaded before we compile it. +(require 'bookmark+-1) ; So be sure to put this library in your `load-path' before + ; trying to byte-compile it. + +;;;;;;;;;;;;;;;;;;;;;;; + +;; Quiet the byte-compiler + +(defvar bmkp-auto-light-when-set) ; In `bookmark+-lit.el' +(defvar bmkp-auto-light-when-jump) ; In `bookmark+-lit.el' +(defvar bmkp-bmenu-buffer) ; In `bookmark+.el' +(defvar bmkp-edit-bookmark-record-mode-map) ; Here, via `define-derived-mode' +(defvar bmkp-edit-bookmark-records-mode-map) ; Here, via `define-derived-mode' +(defvar bmkp-edit-tags-mode-map) ; Here, via `define-derived-mode' +(defvar bmkp-eww-auto-type) ; Here (Emacs 25+) +(defvar bmkp-eww-buffer-renaming) ; Here (Emacs 25+) +(defvar bmkp-eww-generate-buffer-flag) ; Here (Emacs 25+) +(defvar bmkp-eww-jumping-p) ; Here (Emacs 25+) +(defvar bmkp-eww-new-buf-name) ; Here (Emacs 25+) +(defvar bmkp-eww-replace-keys-flag) ; Here (Emacs 25+) +(defvar bmkp-info-auto-type) ; Here (Emacs 22+) +(defvar bmkp-light-priorities) ; In `bookmark+-lit.el' +(defvar bmkp-temporary-bookmarking-mode) ; Here +(defvar bmkp-global-automatic-bookmark-mode) ; Here, via `define-globalized-minor-mode' +(defvar bookmark-current-point) ; In `bookmark.el', but not in Emacs 23+ +(defvar bookmark-edit-annotation-text-func) ; In `bookmark.el' +(defvar bookmark-file-coding-system) ; In `bookmark.el' (Emacs 25.2+) +(defvar bookmark-read-annotation-text-func) ; In `bookmark.el', but not in Emacs 23+ +(defvar bookmark-make-record-function) ; In `bookmark.el' +(defvar desktop-basefilename) ; In `desktop.el' (Emacs < 22) +(defvar desktop-base-file-name) ; In `desktop.el' +(defvar desktop-buffer-args-list) ; In `desktop.el' +(defvar desktop-delay-hook) ; In `desktop.el' +(defvar desktop-dirname) ; In `desktop.el' +(defvar desktop-file-modtime) ; In `desktop.el' +(defvar desktop-globals-to-save) ; In `desktop.el' +(defvar desktop-save-mode) ; In `desktop.el' +(defvar desktop-save) ; In `desktop.el' +(defvar dired-actual-switches) ; In `dired.el' +(defvar dired-buffers) ; In `dired.el' +(defvar dired-directory) ; In `dired.el' +(defvar dired-guess-shell-case-fold-search) ; In `dired-x.el' +(defvar dired-subdir-alist) ; In `dired.el' +(defvar eww-data) ; In `eww.el' (Emacs 25+) +(defvar eww-local-regex) ; In `eww.el' (Emacs 25+) +(defvar eww-search-prefix) ; In `eww.el' (Emacs 25+) +(defvar gnus-article-current) ; In `gnus-sum.el' +(defvar icicle-candidate-properties-alist) ; In `icicles-var.el' +(defvar icicle-completion-candidates) ; In `icicles-var.el' +(defvar icicle-mode) ; In `icicle-mode.el' +(defvar icicle-multi-completing-p) ; In `icicles-var.el' +(defvar icicle-saved-completion-candidates) ; In `icicles-var.el' +(defvar icicle-searching-p) ; In `icicles-var.el' +(defvar Info-current-node) ; In `info.el' +(defvar Info-current-file) ; In `info.el' +(defvar kmacro-counter) ; In `kmacro.el' +(defvar kmacro-counter-format-start) ; In `kmacro.el' +(defvar kmacro-ring) ; In `kmacro.el' +(defvar Man-arguments) ; In `man.el' +(defvar org-store-link-functions) ; In `org.el' +(defvar read-file-name-completion-ignore-case) ; Emacs 23+ +(defvar last-repeatable-command) ; In `repeat.el' +(defvar w3m-current-title) ; In `w3m.el' +(defvar w3m-current-url) ; In `w3m.el' +(defvar w3m-mode-map) ; In `w3m.el' +(defvar zz-izones) ; In `zones.el' +(defvar zz-izones-var) ; In `zones.el' +(defvar woman-last-file-name) ; In `woman.el' + +;;(@* "User Options (Customizable)") +;;; User Options (Customizable) -------------------------------------- + +;;;###autoload (autoload 'bmkp-autofile-access-invokes-bookmark-flag "bookmark+") +(defcustom bmkp-autofile-access-invokes-bookmark-flag nil + "*Non-nil means invoke the bookmark when you access an autofile. +That is, if a file has an associated autofile bookmark then functions +such as `find-file' will automatically jump to the bookmark. The +buffer position of an autofile bookmark is not important, but this can +be useful to update the bookmark data, such as the number of visits. + +If you change the option value in Lisp code without using a Customize +function, then add/remove `bmkp-find-file-invoke-bookmark-if-autofile' +to/from `find-file-hook'." + :set (lambda (sym new-val) + (custom-set-default sym new-val) + (let ((hook-var (if (< emacs-major-version 22) 'find-file-hooks 'find-file-hook))) + (if bmkp-autofile-access-invokes-bookmark-flag + (add-hook hook-var 'bmkp-find-file-invoke-bookmark-if-autofile) + (remove-hook hook-var 'bmkp-find-file-invoke-bookmark-if-autofile)))) + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-autofile-filecache "bookmark+") +(defcustom bmkp-autofile-filecache 'cache-only + "*Whether Emacs filecache commands create/set an autofile bookmark. +The possible values: +`autofile+cache' - Whenever a file is added to the file cache, also + create/set an autofile bookmark for the file. +`autofile-only' - Create/set an autofile instead of caching the file. +`cache-only' - Add the file to the file cache. No autofile." + :type '(choice + (const :tag "Create/set an autofile bookmark instead of adding to file cache" autofile-only) + (const :tag "Create/set an autofile bookmark and add to file cache" autofile+cache) + (const :tag "Add to file cache only - do not create/set an autofile bookmark" cache-only)) + :group 'bookmark-plus) + + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-auto-idle-bookmark-min-distance 'bmkp-automatic-bookmark-min-distance) + (bmkp-make-obsolete-variable 'bmkp-auto-idle-bookmark-min-distance 'bmkp-automatic-bookmark-min-distance + "2021-08-18")) + +;;;###autoload (autoload 'bmkp-automatic-bookmark-min-distance "bookmark+") +(defcustom bmkp-automatic-bookmark-min-distance 1000 + "*Minimum number of chars between automatic bookmark positions. +Automatic bookmarking is done by `bmkp-automatic-bookmark-mode'." + :type '(choice + (const :tag "No minumum distance" nil) + (integer :tag "At least this many chars" :value 1000)) + :group 'bookmark-plus) + +;; Emacs 20 only. +;; +;; (Don't bother aliasing the old name, for Emacs 20.) +;; +;;;###autoload (autoload 'bmkp-automatic-bookmark-mode "bookmark+") +(unless (fboundp 'define-minor-mode) + (defcustom bmkp-automatic-bookmark-mode nil + "*Non-nil means that bookmarks are created periodically automatically. +Setting this variable directly does not take effect; +use either \\[customize] or command `bmkp-automatic-bookmark-mode'." + :set (lambda (symbol value) (bmkp-automatic-bookmark-mode (if value 1 -1))) + :initialize 'custom-initialize-default + :type 'boolean :group 'bookmark-plus :require 'bookmark+)) + + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-auto-idle-bookmark-mode-delay 'bmkp-automatic-bookmark-mode-delay) + (bmkp-make-obsolete-variable 'bmkp-auto-idle-bookmark-mode-delay 'bmkp-automatic-bookmark-mode-delay + "2021-08-18")) + +;;;###autoload (autoload 'bmkp-automatic-bookmark-mode-delay "bookmark+") +(defcustom bmkp-automatic-bookmark-mode-delay 60 + "*Number of seconds delay before automatically setting a bookmark. +Automatic bookmarking is done by `bmkp-automatic-bookmark-mode'." + :type 'integer :group 'bookmark-plus) + + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-auto-idle-bookmark-mode-lighter 'bmkp-automatic-bookmark-mode-lighter) + (bmkp-make-obsolete-variable 'bmkp-auto-idle-bookmark-mode-lighter 'bmkp-automatic-bookmark-mode-lighter + "2021-08-18")) + +;;;###autoload (autoload 'bmkp-automatic-bookmark-mode-lighter "bookmark+") +(defcustom bmkp-automatic-bookmark-mode-lighter " Auto-Bmk" + "*Lighter for `bmkp-automatic-bookmark-mode'. +This string shows in the mode line when `bmkp-automatic-bookmark-mode' +is enabled. Set this to nil or \"\" if you do not want any lighter." + :type 'string :group 'bookmark-plus) + + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-auto-idle-bookmark-mode-set-function 'bmkp-automatic-bookmark-set-function) + (bmkp-make-obsolete-variable 'bmkp-auto-idle-bookmark-mode-set-function + 'bmkp-automatic-bookmark-set-function + "2021-08-18")) + +;;;###autoload (autoload 'bmkp-automatic-bookmark-set-function "bookmark+") +(defcustom bmkp-automatic-bookmark-set-function #'bmkp-set-autonamed-bookmark-at-line + "*Function used to set an automatic bookmark. +Used by `bmkp-automatic-bookmark-mode' and `bmkp-set-automatic-bookmark'. + +The default value, `bmkp-set-autonamed-bookmark-at-line', sets an +autonamed bookmark at the start of the current line. To bookmark the +current position, so you can have more than one automatic bookmark per +line, use `bmkp-set-autonamed-bookmark' instead." + :type 'function :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-autoname-bookmark-function "bookmark+") +(defcustom bmkp-autoname-bookmark-function 'bmkp-autoname-bookmark-function-default + "*Function to automatically name a bookmark at point (cursor position). +It should accept a buffer position as its (first) argument. +The name returned should match the application of +`bmkp-autoname-format' to the buffer name." + :type 'function :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-autoname-format "bookmark+") +(defcustom bmkp-autoname-format (if (> emacs-major-version 21) "^[0-9]\\{9\\} %B" "^[0-9]+ %B") + "*Format string to match an autonamed bookmark name. +You can use `%B' instead of `%s' to accept the buffer name. This has +the advantage that commands and other functions that check for a +buffer-specific bookmark can tell more accurately whether a bookmark +name matches the given buffer. This applies to functions such as +`bmkp-autonamed-this-buffer-jump' and +`bmkp-autonamed-this-buffer-bookmark-p'." + :type 'string :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-autotemp-bookmark-predicates "bookmark+") +(defcustom bmkp-autotemp-bookmark-predicates '(bmkp-autonamed-bookmark-p + bmkp-autonamed-this-buffer-bookmark-p) + "*Predicates for bookmarks to be set (created) as temporary bookmarks. +Each is typically a type predicate, but it can be any function that +accepts as its (first) argument a bookmark or bookmark name. + +These are the predefined type predicates: + +`bmkp-annotated-bookmark-p', `bmkp-autofile-bookmark-p', +`bmkp-autonamed-bookmark-for-buffer-p', `bmkp-autonamed-bookmark-p', +`bmkp-autonamed-this-buffer-bookmark-p', `bmkp-buffer-bookmark-p', +`bmkp-bookmark-file-bookmark-p', `bmkp-bookmark-list-bookmark-p', +`bmkp-desktop-bookmark-p', `bmkp-dired-bookmark-p', +`bmkp-dired-this-dir-bookmark-p', `bmkp-dired-wildcards-bookmark-p', +`bmkp-eww-bookmark-p' (Emacs 25+), `bmkp-file-bookmark-p', +`bmkp-file-remote-p', `bmkp-file-this-dir-bookmark-p', +`bmkp-flagged-bookmark-p', `bmkp-function-bookmark-p', +`bmkp-gnus-bookmark-p', `bmkp-icicles-search-hits-bookmark-p', +`bmkp-image-bookmark-p', `bmkp-info-bookmark-p', +`bmkp-last-specific-buffer-p', `bmkp-last-specific-file-p', +`bmkp-local-directory-bookmark-p', `bmkp-local-file-bookmark-p', +`bmkp-local-non-dir-file-bookmark-p', `bmkp-man-bookmark-p', +`bmkp-marked-bookmark-p', `bmkp-modified-bookmark-p', +`bmkp-navlist-bookmark-p', `bmkp-non-dir-file-bookmark-p', +`bmkp-non-file-bookmark-p', `bmkp-non-invokable-bookmark-p', +`bmkp-omitted-bookmark-p', `bmkp-orphaned-file-bookmark-p', +`bmkp-orphaned-local-file-bookmark-p', +`bmkp-orphaned-remote-file-bookmark-p', `bmkp-region-bookmark-p', +`bmkp-remote-file-bookmark-p', `bmkp-remote-non-dir-file-bookmark-p', +`bmkp-sequence-bookmark-p', `bmkp-snippet-bookmark-p', +`bmkp-temporary-bookmark-p', `bmkp-this-buffer-p', `bmkp-this-file-p', +`bmkp-url-bookmark-p', `bmkp-url-browse-bookmark-p', +`bmkp-variable-list-bookmark-p', `bmkp-w3m-bookmark-p'" + :type '(repeat symbol) :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-bookmark-name-length-max "bookmark+") +(defcustom bmkp-bookmark-name-length-max 70 + "*Max number of chars for default name for a bookmark with a region." + :type 'integer :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-count-multi-mods-as-one-flag "bookmark+") +(defcustom bmkp-count-multi-mods-as-one-flag t + "*Non-nil means count multiple modifications as one. +This is for `bookmark-alist-modification-count'. Non-nil means that +when you invoke a command that acts on multiple bookmarks or acts in +multiple ways on one bookmark, all of changes together count as only +one modification. That can prevent automatic saving of your bookmark +file during the sequence of modifications, so that when the command is +done you can choose not to save (i.e., to quit) if you like." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-crosshairs-flag "bookmark+") +(defcustom bmkp-crosshairs-flag (> emacs-major-version 21) + "*Non-nil means highlight with crosshairs when you visit a bookmark. +The highlighting is temporary - until your next action. +You need library `crosshairs.el' for this feature, and you need Emacs +22 or later. + +NOTE: Crosshairs highlighting is shown in the buffer that is current +after jumping. If the bookmarked jumped to does not really have an +associated buffer, for example a bookmark with a handler such as +`w32-browser' that just invokes a separate, non-Emacs program, then +the current buffer after jumping will be the buffer before jumping. + +If you use this option in Lisp code, you will want to add/remove +`bmkp-crosshairs-highlight' to/from `bookmark-after-jump-hook'." + :set (lambda (sym new-val) + (custom-set-default sym new-val) + (if (and bmkp-crosshairs-flag (> emacs-major-version 21) + (condition-case nil (require 'crosshairs nil t) (error nil))) + (add-hook 'bookmark-after-jump-hook 'bmkp-crosshairs-highlight) + (remove-hook 'bookmark-after-jump-hook 'bmkp-crosshairs-highlight))) + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-default-bookmark-name "bookmark+") +(defcustom bmkp-default-bookmark-name 'highlighted + "*Default bookmark name preference for accessing existing bookmarks. +\(The default name for a *new* bookmark is obtained using option +`bmkp-new-bookmark-default-names'.) + +In `*Bookmark List*' use the name of the current line's bookmark. +Otherwise, if `bookmark+-lit.el' is not loaded then use the name of +the last-used bookmark in the current file. + +Otherwise, use this option to determine the default, by preferring one +of the following, if available: + +* a highlighted bookmark at point +* the last-used bookmark in the current file" + :type '(choice + (const :tag "Highlighted bookmark at point" highlighted) + (const :tag "Last used bookmark in same file" last-used)) + :group 'bookmark-plus) + + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-default-handler-associations 'bmkp-default-handlers-for-file-types) + (bmkp-make-obsolete-variable 'bmkp-default-handler-associations 'bmkp-default-handlers-for-file-types + "2012-02-27")) + +;;;###autoload (autoload 'bmkp-default-handlers-for-file-types "bookmark+") +(defcustom bmkp-default-handlers-for-file-types + (and (require 'dired-x) ; It in turn requires `dired-aux.el' + (eval-when-compile (when (< emacs-major-version 21) (require 'cl))) ;; `dolist', for Emacs 20 + (let ((assns ())) + (dolist (shell-assn dired-guess-shell-alist-user) + (push (cons (car shell-assn) + `(lambda (bmk) + (dired-run-shell-command + (dired-shell-stuff-it ,(cadr shell-assn) (list (bookmark-get-filename bmk)) + nil nil)))) + assns)) + assns)) + "*File associations for bookmark handlers used for indirect bookmarks. +Each element of the alist is (REGEXP . COMMAND). +REGEXP matches a file name. +COMMAND is a sexp that evaluates to either a shell command (a string) + or an Emacs function (a symbol or a lambda form). The shell command + or Lisp function must accept a file-name argument. + +Example value: + + ((\"\\\\.pdf$\" . \"AcroRd32.exe\") ; Adobe Acrobat Reader + (\"\\\\.ps$\" . \"gsview32.exe\") ; Ghostview (PostScript viewer) + (\"\\\\.html?$\" . browse-url) ; Use Lisp function `browse-url' + (\"\\\\.doc$\" . w32-browser)) ; Use Lisp function `w32-browser' + +When you change this option using Customize, if you want to use a +literal string as COMMAND then you must double-quote the text: +\"...\". (But do not use double-quotes for the REGEXP.) If you want +to use a symbol as COMMAND, just type the symbol name (no quotes). + +This option is used by `bmkp-default-handler-for-file' to determine +the default `file-handler' property for a given file bookmark. If a +given file name does not match this option, and if +`bmkp-guess-default-handler-for-file-flag' is non-nil, then +`bmkp-default-handler-for-file' tries to guess a shell command to use +in the default handler. For that it uses `dired-guess-default' and +\(Emacs 23+ only) mailcap entries, in that order." + :type '(alist :key-type + regexp :value-type + (sexp :tag "Shell command (string) or Emacs function (symbol or lambda form)")) + :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-desktop-default-directory "bookmark+") +(defcustom bmkp-desktop-default-directory nil + "*Default directory used when reading the name of a desktop file. +If nil then use the current directory (value of `default-directory')." + :type 'directory :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-desktop-jump-save-before-flag "bookmark+") +(defcustom bmkp-desktop-jump-save-before-flag nil + "*Non-nil means `bmkp-desktop-jump' saves the desktop file before switching." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-desktop-no-save-vars "bookmark+") +(defcustom bmkp-desktop-no-save-vars '(search-ring regexp-search-ring kill-ring) + "*List of variables not to save when creating a desktop bookmark. +They are removed from `desktop-globals-to-save' for the duration of +the save (only)." + :type '(repeat (variable :tag "Variable")) :group 'bookmark-plus) + + +;; EWW support +(when (> emacs-major-version 24) ; Emacs 25+ + + (defcustom bmkp-eww-auto-type 'update-only + "How `bmkp-eww-auto-bookmark-mode' behaves when enabled. +You can toggle this option using `\\[bmkp-toggle-eww-auto-type]'." + :type '(choice + (const :tag "Create EWW bookmark or update existing EWW bookmark" create-or-update) + (const :tag "Update existing EWW bookmark (only)" update-only)) + :group 'bookmark-plus) + + ;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs + ;; works for newer Emacs too. + (defvaralias 'bmkp-eww-buffer-handling 'bmkp-eww-buffer-renaming) + (bmkp-make-obsolete-variable 'bmkp-eww-buffer-handling 'bmkp-eww-buffer-renaming "2018-02-23") + + (defcustom bmkp-eww-buffer-renaming nil + "Whether and how an EWW buffer is renamed. +Non-nil values affect EWW behavior even when bookmarks are not used. + +* nil: Do not rename buffer - use `*eww*' (vanilla EWW behavior). +* `url': Rename buffer to web-page title plus last 20 chars of URL. +* `page': Rename buffer to web-page title (only)." + :type '(choice + (const :tag "Do not rename buffer (use name `*eww*')" nil) + (const :tag "Rename buffer to web-page title plus last 20 chars of URL" url) + ;; Any symbol other than `page' and nil is treated the same as `page'. + (const :tag "Rename buffer to web-page title" page)) + :group 'bookmark-plus) + + (defcustom bmkp-eww-generate-buffer-flag nil + "Whether to generate a new buffer when jumping to an EWW bookmark. +* nil means reuse an existing buffer for the bookmarked URL. +* Non-nil means use a new buffer." + :type 'boolean :group 'bookmark-plus) + + ;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs + ;; works for newer Emacs too. + (defvaralias 'bmkp-replace-eww-keys-flag 'bmkp-eww-replace-keys-flag) + (bmkp-make-obsolete-variable 'bmkp-replace-eww-keys-flag 'bmkp-eww-replace-keys-flag "2017-01-10") + + (defcustom bmkp-eww-replace-keys-flag t + "Non-nil means replace EWW bookmarking keys and menus with Bookmark+ ones. +If you change the value of this option then you must restart Emacs for +it to take effect." + :type 'boolean :group 'bookmark-plus) + ) + +;;;###autoload (autoload 'bmkp-annotation-modes-inherit-from "bookmark+") +(defcustom bmkp-annotation-modes-inherit-from (if (fboundp 'org-mode) 'org-mode 'text-mode) + "Symbol for mode that bookmark annotation modes are to inherit from. +Or nil if no parent mode. The annotation modes are +`bmkp-edit-annotation-mode' and `bmkp-show-annotation-mode'. + +You must restart Emacs after changing the value of this option, for +the change to take effect." + :type 'symbol :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-handle-region-function "bookmark+") +(defcustom bmkp-handle-region-function 'bmkp-handle-region-default + "*Function to handle a bookmarked region." + :type 'function :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-info-sort-ignores-directories-flag "bookmark+") +(defcustom bmkp-info-sort-ignores-directories-flag t + "*Non-nil means Info-bookmark sorting uses manual names, not file locations. +If nil, the absolute file names of the manuals are used. This can be +useful if you have bookmarks for multiple Emacs releases, and you want +the bookmarks for a given release to appear together." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-incremental-filter-delay "bookmark+") +(defcustom bmkp-incremental-filter-delay (if (boundp 'bookmark-search-delay) + bookmark-search-delay + 0.2) + "*Seconds to wait before updating display when filtering bookmarks." + :type 'number :group 'bookmark-plus) + + +(when (> emacs-major-version 21) ; Emacs 22+ (need also `Info-selection-hook'). + + (defcustom bmkp-info-auto-type 'create-or-update + "How `bmkp-info-auto-bookmark-mode' behaves when enabled. +You can toggle this option using `\\[bmkp-toggle-info-auto-type]'." + :type '(choice + (const :tag "Create Info bookmark or update existing Info bookmark" create-or-update) + (const :tag "Update existing Info bookmark (only)" update-only)) + :group 'bookmark-plus) + + ) + +;; Removed autoload cookie, to avoid (void-variable bookmark-default-file) ;;;###autoload +(defcustom bmkp-last-as-first-bookmark-file bookmark-default-file + "*Whether to use the last-used bookmark file as the first used. +If nil then Emacs always uses the value of `bookmark-default-file' as +the initial bookmark file, in any given session. + +If non-nil, Emacs uses the last bookmark file you used, in the last +Emacs session. If none was recorded then it uses +`bookmark-default-file'. The particular non-nil value must be an +absolute file name \(possibly containing `~') - it is not expanded). + +NOTE: A non-nil option value is overwritten by Bookmark+, so that it +becomes the last-used bookmark file. A nil value is never +overwritten." + :type '(choice + (const :tag "Use `bookmark-default-file' as initial bookmark file" nil) + (file :tag "Use last-used bookmark file as initial bookmark file" + :value "~/.emacs.bmk")) + :group 'bookmark) + +;;;###autoload (autoload 'bmkp-menu-popup-max-length "bookmark+") +(defcustom bmkp-menu-popup-max-length 20 + "*Max number of bookmarks for `bookmark-completing-read' to use a menu. +When choosing a bookmark from a list of bookmarks using +`bookmark-completing-read', this controls whether to use a menu or +minibuffer input with completion. +If t, then always use a menu. +If nil, then never use a menu. +If an integer, then use a menu only if there are fewer bookmark + choices than the value." + :type '(choice + (integer :tag "Use a menu if there are fewer bookmark choices than this" 20) + (const :tag "Always use a menu to choose a bookmark" t) + (const :tag "Never use a menu to choose a bookmark" nil)) + :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-new-bookmark-default-names "bookmark+") +(defcustom bmkp-new-bookmark-default-names + (let ((fns '((lambda () (let ((ff (function-called-at-point))) + (and ff (symbolp ff) (symbol-name ff))))))) + (when (fboundp 'region-or-non-nil-symbol-name-nearest-point) ; Defined in `thingatpt+.el'. + (setq fns (cons 'region-or-non-nil-symbol-name-nearest-point fns))) + fns) + "Functions to produce the default name for a new bookmark. +\(The default name for an *existing* bookmark is obtained using +`bmkp-default-bookmark-name'.) + +The option value is a list of functions that do not require an +argument and return a string (or nil). They are invoked, in order, to +produce the default names. + +The following names are also provided, after the names described +above: The value of variable `bookmark-current-bookmark' and the +return value of function `bookmark-buffer-name', in that order. + +These latter names are the defaults provided by vanilla Emacs +`bookmark.el', so if you want the vanilla behavior then set the option +value to nil. + +For non-interactive use of a default bookmark name, and for Emacs +prior to Emacs 23 even for interactive use, only the first default +name is used. + +Some functions you might want to use in the option value: + + * `region-or-non-nil-symbol-name-nearest-point' + * (lambda () (let ((ff (function-called-at-point))) + (and (symbolp ff) (symbol-name ff)))) + * (lambda () (let ((vv (variable-at-point))) ; `variable-at-point' + (and (symbolp vv) (symbol-name vv)))) ; returns 0 if no var + * `word-at-point' + * (lambda () (let ((ss (symbol-at-point))) + (and ss (symbol-name ss)))) + +The first of these is defined in library `thingatpt+.el'. It returns +the text in the region, if it is active and not empty. Otherwise it +returns the name of the (non-`nil') symbol nearest point, within +maximum search distances `tap-near-point-x-distance' (left and right) +and `tap-near-point-y-distance' (up and down)." + :type '(repeat function) :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-other-window-pop-to-flag "bookmark+") +(defcustom bmkp-other-window-pop-to-flag t + "*Non-nil means other-window bookmark jumping uses `pop-to-buffer'. +Use nil if you want the vanilla Emacs behavior, which uses +`switch-to-buffer-other-window'. That creates a new window even if +there is already another window showing the buffer." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-prompt-for-tags-flag "bookmark+") +(defcustom bmkp-prompt-for-tags-flag nil + "*Non-nil means setting bookmarks interactively prompts for tags to add. +For an existing bookmark, if option `bmkp-properties-to-keep' includes +`tags' (which it does by default), then the tags you enter are added +to any that the bookmark already has - none are removed." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-properties-to-keep "bookmark+") +(defcustom bmkp-properties-to-keep '(tags annotation) + "*List of properties to keep when you set an existing bookmark. +When you set a bookmark that already exists, its properties are +updated (overwritten), with the exception of those listed here." + :type '(repeat symbol) :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-region-search-size "bookmark+") +(defcustom bmkp-region-search-size 40 + "*Same as `bookmark-search-size', but specialized for bookmark regions." + :type 'integer :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-save-new-location-flag "bookmark+") +(defcustom bmkp-save-new-location-flag t + "*Non-nil means save automatically relocated bookmarks. +If nil, then the new bookmark location is visited, but it is not saved +as part of the bookmark definition." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-sequence-jump-display-function "bookmark+") +(defcustom bmkp-sequence-jump-display-function 'pop-to-buffer + "*Function used to display the bookmarks in a bookmark sequence." + :type 'function :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-show-end-of-region-flag "bookmark+") +(defcustom bmkp-show-end-of-region-flag t + "*Show end of region with `exchange-point-and-mark' when activating a region. +If nil show only beginning of region." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-sort-comparer "bookmark+") +(defcustom bmkp-sort-comparer '((bmkp-info-node-name-cp bmkp-gnus-cp bmkp-url-cp bmkp-local-file-type-cp) + bmkp-alpha-p) ; This corresponds to `s k'. + ;; $$$$$$ An alternative default value: `bmkp-alpha-p', which corresponds to `s n'. + "*Predicate or predicates for sorting (comparing) bookmarks. +This defines the default sort for bookmarks in the bookmark list. + +Various sorting commands, such as \\\ +`\\[bmkp-bmenu-sort-by-bookmark-visit-frequency]', change the value of this +option dynamically (but they do not save the changed value). + +The value must be one of the following: + +* nil, meaning do not sort + +* a predicate that takes two bookmarks as args + +* a list of the form ((PRED...) FINAL-PRED), where each PRED and + FINAL-PRED are predicates that take two bookmarks as args + +If the value is a list of predicates, then each PRED is tried in turn +until one returns a non-nil value. In that case, the result is the +car of that value. If no non-nil value is returned by any PRED, then +FINAL-PRED is used and its value is the result. + +Each PRED should return `(t)' for true, `(nil)' for false, or nil for +undecided. A nil value means that the next PRED decides (or +FINAL-PRED, if there is no next PRED). + +Thus, a PRED is a special kind of predicate that indicates either a +boolean value (as a singleton list) or \"I cannot decide - let the +next guy else decide\". (Essentially, each PRED is a hook function +that is run using `run-hook-with-args-until-success'.) + +Examples: + + nil - No sorting. + + string-lessp - Single predicate that returns nil or non-nil. + + ((p1 p2)) - Two predicates `p1' and `p2', which each return + (t) for true, (nil) for false, or nil for undecided. + + ((p1 p2) string-lessp) + - Same as previous, except if both `p1' and `p2' return + nil, then the return value of `string-lessp' is used. + +Note that these two values are generally equivalent, in terms of their +effect (*): + + ((p1 p2)) + ((p1) p2-plain) where p2-plain is (bmkp-make-plain-predicate p2) + +Likewise, these three values generally act equivalently (*): + + ((p1)) + (() p1-plain) + p1-plain where p1-plain is (bmkp-make-plain-predicate p1) + +The PRED form lets you easily combine predicates: use `p1' unless it +cannot decide, in which case try `p2', and so on. The value ((p2 p1)) +tries the predicates in the opposite order: first `p2', then `p1' if +`p2' returns nil. + +Using a single predicate or FINAL-PRED makes it easy to reuse an +existing predicate that returns nil or non-nil. + +You can also convert a PRED-type predicate (which returns (t), (nil), +or nil) into an ordinary predicate, by using function +`bmkp-make-plain-predicate'. That lets you reuse elsewhere, as +ordinary predicates, any PRED-type predicates you define. + +For example, this defines a plain predicate to compare by URL: + (defalias 'bmkp-url-p (bmkp-make-plain-predicate 'bmkp-url-cp)) + +Note: As a convention, predefined Bookmark+ PRED-type predicate names +have the suffix `-cp' (for \"component predicate\") instead of `-p'. + +-- +* If you use `\\[bmkp-reverse-multi-sort-order]', then there is a difference in \ +behavior between + + (a) using a plain predicate as FINAL-PRED and + (b) using the analogous PRED-type predicate (and no FINAL-PRED). + + In the latter case, `\\[bmkp-reverse-multi-sort-order]' affects when the predicate \ +is tried and + its return value. See `bmkp-reverse-multi-sort-order'." + :type '(choice + (const :tag "None (do not sort)" nil) + (function :tag "Sorting Predicate") + (list :tag "Sorting Multi-Predicate" + (repeat (function :tag "Component Predicate")) + (choice + (const :tag "None" nil) + (function :tag "Final Predicate")))) + :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-su-or-sudo-regexp "bookmark+") +(defcustom bmkp-su-or-sudo-regexp "\\(/su:\\|/sudo:\\)" + "*Regexp to recognize `su' or `sudo' Tramp bookmarks." + :type 'regexp :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-tags-for-completion "bookmark+") +(defcustom bmkp-tags-for-completion 'current + "*List of strings used as tags for completion (not an alist). +The tags can be specified here individually or taken from (a) the +current bookmark list or (b) one or more bookmark files or both. + +\(In Emacs 20 and 21, you cannot choose (b) when customizing, but if +\(b) was chosen using a later Emacs version then the option value can +still be used in Emacs 20 and 21.) + +If a relative file name is specified for a bookmark file then the +current value of `default-directory' is used to find the file." + :type (if (> emacs-major-version 21) + '(choice + (const :tag "From current bookmarks only" current) + (list :tag "From current bookmarks and other sources" + (const :tag "" current) + (repeat :inline t :tag "Additional sources or specific tags" + (choice + (string :tag "Specific tag") + (cons :tag "All tags from a bookmark file" + (const :tag "" bmkfile) (file :must-match t))))) + (repeat :tag "Choose sources or specific tags" + (choice + (string :tag "Specific tag") + (cons :tag "All tags from a bookmark file" + (const :tag "" bmkfile) (file :must-match t))))) + ;; A bug in Emacs 20-21 means we must sacrifice the user choice of current plus other sources. + '(choice + (const :tag "From current bookmarks only" current) + (repeat :tag "Choose sources or specific tags" ; A 2nd Emacs 20-21 bug ignores `:tag' for menu. + (choice + (string :tag "Specific tag") + (cons :tag "All tags from a bookmark file" + (const :tag "" bmkfile) (file :must-match t)))))) + :group 'bookmark-plus) + +;; Emacs 20 only. +(unless (fboundp 'define-minor-mode) + (defcustom bmkp-temporary-bookmarking-mode nil + "*Non-nil means that bookmarks are temporary (not recorded on disk). +Setting this variable directly does not take effect; +use either \\[customize] or command `bmkp-temporary-bookmarking-mode'." + :set (lambda (symbol value) (bmkp-temporary-bookmarking-mode (if value 1 -1))) + :initialize 'custom-initialize-default + :type 'boolean :group 'bookmark-plus :require 'bookmark+)) + +;;;###autoload (autoload 'bmkp-temporary-bookmarking-mode-hook "bookmark+") +(defcustom bmkp-temporary-bookmarking-mode-hook () + "*Functions run after entering and exiting temporary-bookmarking mode." + :type 'hook :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-this-file/buffer-cycle-sort-comparer "bookmark+") +(defcustom bmkp-this-file/buffer-cycle-sort-comparer '((bmkp-position-cp)) + "*`bmkp-sort-comparer' value for cycling this-file/buffer bookmarks. +Use bookmarks for the currently visited file or (non-file) buffer. +Some values you might want to use: ((bmkp-position-cp)), + ((bmkp-bookmark-creation-cp)), ((bmkp-visited-more-cp)). +See `bmkp-sort-comparer'." + :type '(choice + (const :tag "None (do not sort)" nil) + (function :tag "Sorting Predicate") + (list :tag "Sorting Multi-Predicate" + (repeat (function :tag "Component Predicate")) + (choice + (const :tag "None" nil) + (function :tag "Final Predicate")))) + :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-guess-default-handler-for-file-flag "bookmark+") +(defcustom bmkp-guess-default-handler-for-file-flag nil + "*Non-nil means guess the default handler when creating a file bookmark. +This is ignored if a handler can be found using option +`bmkp-default-handlers-for-file-types'. Otherwise, this is used by +function `bmkp-default-handler-for-file' to determine the default +handler for a given file." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-read-bookmark-file-hook "bookmark+") +(defcustom bmkp-read-bookmark-file-hook () + "*List of functions called, in order, after reading a bookmark file. +Each function should accept the list of bookmarks read from the file +as first argument and the bookmark file name as second argument." + :type 'hook :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-temporary-bookmarking-mode-lighter "bookmark+") +(defcustom bmkp-temporary-bookmarking-mode-lighter " Temp-Bmk" + "*Lighter for `bmkp-temporary-bookmarking-mode'. +This string shows in the mode line when `bmkp-temporary-bookmarking-mode' +is enabled. Set this to nil or \"\" if you do not want any lighter." + :type 'string :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-use-region "bookmark+") +(defcustom bmkp-use-region t + "*Non-nil means visiting a bookmark activates its recorded region." + :type '(choice + (const :tag "Activate bookmark region (except during cycling)" t) + (const :tag "Do not activate bookmark region" nil) + (const :tag "Activate bookmark region even during cycling" cycling-too)) + :group 'bookmark-plus) + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +;;;###autoload (autoload 'bmkp-w3m-allow-multiple-buffers-flag "bookmark+") +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-w3m-allow-multi-tabs-flag 'bmkp-w3m-allow-multiple-buffers-flag)) +(bmkp-make-obsolete-variable 'bmkp-w3m-allow-multi-tabs-flag 'bmkp-w3m-allow-multiple-buffers-flag + "2017-01-10") + +(defcustom bmkp-w3m-allow-multiple-buffers-flag t + "*Non-nil means jump to a W3M bookmark in a new buffer." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-write-bookmark-file-hook "bookmark+") +(defcustom bmkp-write-bookmark-file-hook () + "*List of functions called, in order, after writing a bookmark file. +Each function should accept the bookmark file name as first argument. +Used after `after-save-hook'." + :type 'hook :group 'bookmark-plus) + +;; This and the version of function `Info-bookmark-jump' defined here are also defined in `info+.el', +;; so that their feature is available if you use either `Info+' or `Bookmark+'. +;; +;;;###autoload +(defcustom Info-bookmark-use-only-node-not-file-flag t + "Non-nil means an Info bookmark uses only the node name. +The recorded Info file name is ignored. This means use only manuals +corresponding to the current Emacs session, regardless of the Emacs +version or platform used to record the bookmark. + +A nil value means use the manuals whose absolute file names are +recorded in the bookmarks. (But if the file doesn't exist or is +unreadable, then act as if the value is non-nil.) + +A non-nil value means you can use the same bookmark with different +Emacs installations, including on different platforms. A nil value +means that you can use a bookmark to consult the Info manual for a +different Emacs version from that of the current session." + :type 'boolean :group 'bookmark-plus) + +;;(@* "Internal Variables") +;;; Internal Variables ----------------------------------------------- + +(defconst bmkp-non-file-filename " - no file -" + "Name to use for `filename' entry, for non-file bookmarks.") + +(defvar bmkp-after-set-hook nil "Hook run after `bookmark-set' sets a bookmark.") + +(defvar bmkp-automatic-bookmarks () + "Alist of bookmarks that were created automatically during this session.") + + +;; We do not use `define-obsolete-variable-alias' so that byte-compilation in older Emacs +;; works for newer Emacs too. +(when (fboundp 'defvaralias) ; Emacs 22+ + (defvaralias 'bmkp-automatic-bookmark-mode-timer 'bmkp-auto-idle-bookmark-mode-timer) + (bmkp-make-obsolete-variable 'bmkp-auto-idle-bookmark-mode-timer 'bmkp-automatic-bookmark-mode-timer + "2021-08-18")) + +(defvar bmkp-automatic-bookmark-mode-timer nil + "Timer for `bmkp-automatic-bookmark-mode'. +This variable is buffer-local, which means that there is a separate +timer for each buffer where automatic bookmarking is enabled. + +NOTE: For Emacs 20, the variable is not buffer-local, by default. To +make it so, do this: + + (make-variable-buffer-local 'bmkp-automatic-bookmark-mode-timer)") + +(unless (< emacs-major-version 21) (make-variable-buffer-local 'bmkp-automatic-bookmark-mode-timer)) + + +(defvar bmkp-autotemp-all-when-set-p nil "Non-nil means make any bookmark temporary whenever it is set.") + +;;; $$$$$$ No - don't bother. +;;; (defconst bmkp-bookmark-modifier-functions '(bookmark-prop-set bmkp-replace-existing-bookmark +;;; bookmark-set-name bookmark-store) +;;; "List of functions that modify bookmarks. +;;; Used to mark modified, unsaved bookmarks, in `*Bookmark List*'. +;;; Should not include any function that calls another in the list.") + + +;; `defvar' Provided for older Emacs versions. +(defvar bookmark-after-jump-hook nil + "Hook run after `bookmark-jump' jumps to a bookmark. +Useful for example to unhide text in `outline-mode'.") + +(defvar bmkp-before-jump-hook nil + "Hook run before `bookmark-jump' jumps to a bookmark.") + +(defvar bmkp-copied-tags () + "List of tags copied from a bookmark, for pasting to other bookmarks.") + +(defvar bmkp-bookmark-set-confirms-overwrite-p nil + "Non-nil means `bookmark-set' requires confirmation about overwriting.") + +(defvar bmkp-current-bookmark-file bookmark-default-file + "Current bookmark file. +When you start Emacs, this is initialized according to +`bmkp-last-as-first-bookmark-file'. + +When you load bookmarks using `\\[bmkp-switch-bookmark-file-create]', this is set to the file you +load. When you save bookmarks using `bookmark-save' with no prefix +arg, they are saved to this file. + +Loading a bookmark file does not change the value of +`bookmark-default-file', but it might change the value of +`bmkp-last-as-first-bookmark-file' (which see). The value of +`bookmark-default-file' is never changed, except by your +customizations.") + +(defvar bmkp-desktop-current-file nil + "Desktop file from last desktop bookmark jumped to.") + +(defvar bmkp-edit-bookmark-orig-record nil + "Record of bookmark being edited.") + +(defvar bmkp-ffap-max-region-size 1024 ; See also Emacs bug #25243. + "Max size of active region used to obtain file-name defaults. +An active region larger than this many characters prevents +`bmkp-ffap-guesser' from calling `ffap-guesser'.") + +(defvar bmkp-file-bookmark-handlers '(bmkp-jump-dired image-bookmark-jump) + "List of functions that handle file or directory bookmarks. +This is used to determine `bmkp-file-bookmark-p'.") + +(defvar bmkp-icicles-search-hits-retrieve-more nil + "Non-nil means add hits recorded in bookmark to current search hits. +Otherwise, replace current with bookmark hits.") + +(defvar bmkp-last-bmenu-state-file nil "Last value of option `bmkp-bmenu-state-file'.") + +(defvar bmkp-last-bookmark-file bookmark-default-file + "Last bookmark file used in this session (or default bookmark file). +This is a backup for `bmkp-current-bookmark-file'.") + +(defvar bmkp-current-nav-bookmark nil "Current bookmark for navigation.") + +(defvar bmkp-jump-display-function nil "Function used currently to display a bookmark.") + +(defvar bmkp-last-specific-buffer "" + "Name of buffer used by `bmkp-last-specific-buffer-p'.") + +(defvar bmkp-last-specific-file "" + "(Absolute) file name used by `bmkp-last-specific-file-p'.") + +(defvar bmkp-modified-bookmarks () + "Alist of bookmarks that have been modified and not saved.") + +(defvar bmkp-nav-alist () "Current bookmark alist used for navigation.") + +(defvar bmkp-return-buffer nil "Name of buffer to return to.") + +(defvar bmkp-reverse-sort-p nil "Non-nil means the sort direction is reversed.") + +(defvar bmkp-reverse-multi-sort-p nil + "Non-nil means the truth values returned by predicates are complemented. +This changes the order of the sorting groups, but it does not in +general reverse that order. The order within each group is unchanged +\(not reversed).") + +(defvar bmkp-use-w32-browser-p nil + "Non-nil means use `w32-browser' in the default bookmark handler. +That is, use the default Windows application for the bookmarked file. +This has no effect if function `w32-browser' is not defined.") + +(defvar bmkp-latest-bookmark-alist () "Copy of `bookmark-alist' as last filtered.") + +(defvar bmkp-last-save-flag-value nil "Last value of option `bookmark-save-flag'.") + +(defvar bmkp-sorted-alist () + "Copy of current bookmark alist, as sorted for buffer `*Bookmark List*'. +Has the same structure as `bookmark-alist'.") + +(defvar bmkp-tag-history () "History of tags read from the user.") + +(defvar bmkp-tags-alist () + "Alist of all bookmark tags, per option `bmkp-tags-for-completion'. +Each entry is a full tag: a cons whose car is a tag name, a string. +This is set by function `bmkp-tags-list'. +Use that function to update the value.") + + +;; REPLACES ORIGINAL DOC STRING in `bookmark.el'. +;; +;; Doc string does not say that the file that was loaded is `bookmark-default-file'. +;; +(defvar bookmarks-already-loaded nil + "Non-nil means some bookmarks have been loaded during this Emacs session.") + + +;; REPLACES ORIGINAL DOC STRING in `bookmark.el'. +;; +;; Doc string reflects `Bookmark+' enhancements. +;; +(put 'bookmark-alist 'variable-documentation + "Current list of bookmarks (bookmark records). +Bookmark functions update the value automatically. +You probably do not want to change the value yourself. + +The value is an alist with entries of the form + (BOOKMARK-NAME . PARAM-ALIST) +or the deprecated form (BOOKMARK-NAME PARAM-ALIST). + + BOOKMARK-NAME is the name you gave to the bookmark when creating it. + PARAM-ALIST is an alist of bookmark data. The order of the entries + in PARAM-ALIST is not important. The possible entries are described + below. + +Bookmarks created using vanilla Emacs (`bookmark.el'): + + (filename . FILENAME) + (location . LOCATION) + (position . POS) + (front-context-string . STR-AFTER-POS) + (rear-context-string . STR-BEFORE-POS) + (handler . HANDLER) + (annotation . ANNOTATION) + + FILENAME names the bookmarked file. + LOCATION names the bookmarked file, URL, or other place (Emacs 23+). + FILENAME or LOCATION is what is shown in the bookmark list + (`C-x r l') when you use `M-t'. + POS is the bookmarked buffer position (position in the file). + STR-AFTER-POS is buffer text that immediately follows POS. + STR-BEFORE-POS is buffer text that immediately precedes POS. + ANNOTATION is a string that you can provide to identify the bookmark. + See options `bookmark-use-annotations' and + `bookmark-automatically-show-annotations'. + HANDLER is a function that provides the bookmark-jump behavior + for a specific kind of bookmark. This is the case for Info + bookmarks, for instance (starting with Emacs 23). + +Bookmarks created using Bookmark+ are the same as for vanilla Emacs, +except for the following differences. + +1. Visit information is recorded, using entries `visits' and `time': + + (visits . NUMBER-OF-VISITS) + (time . TIME-LAST-VISITED) + + NUMBER-OF-VISITS is a whole-number counter. + + TIME-LAST-VISITED is an Emacs time representation, such as is + returned by function `current-time'. + +2. The buffer name is recorded, using entry `buffer-name'. It need +not be associated with a file. + +3. If no file is associated with the bookmark, then FILENAME is + ` - no file -'. + +4. Bookmarks can be tagged by users. The tag information is recorded +using entry `tags': + + (tags . TAGS-ALIST) + + TAGS-ALIST is an alist with string keys. + +5. A bookmark can be simply a wrapper for a file, in which case it has +entry `file-handler' instead of `handler'. When you \"jump\" to such +a bookmark, the `file-handler' function or shell-command is applied to +the `filename' entry. Any `handler' entry present is ignored, as are +entries such as `position'. It is only the target file that is +important. + +6. Bookmarks can have individual highlighting, provided by users. +This overrides any default highlighting. + + (lighting . HIGHLIGHTING) + + HIGHLIGHTING is a property list that contain any of these keyword + pairs: + + `:style' - Highlighting style. Cdrs of `bmkp-light-styles-alist' + entries are the possible values. + `:face' - Highlighting face, a symbol. + `:when' - A sexp to be evaluated. Return value of `:no-light' + means do not highlight. + +7. The following additional entries are used to record region +information. When a region is bookmarked, POS represents the region +start position. + + (end-position . END-POS) + (front-context-region-string . STR-BEFORE-END-POS) + (rear-context-region-string . STR-AFTER-END-POS)) + + END-POS is the region end position. + STR-BEFORE-END-POS is buffer text that precedes END-POS. + STR-AFTER-END-POS is buffer text that follows END-POS. + +The two context region strings are non-nil only when a region is +bookmarked. + + NOTE: The relative locations of `front-context-region-string' and + `rear-context-region-string' are reversed from those of + `front-context-string' and `rear-context-string'. For example, + `front-context-string' is the text that *follows* `position', but + `front-context-region-string' *precedes* `end-position'. + +8. The following additional entries are used for a Dired bookmark. + + (dired-marked . MARKED-FILES) + (dired-subdirs . INSERTED-SUBDIRS) + (dired-hidden-dirs . HIDDEN-SUBDIRS) + (dired-switches . SWITCHES) + + MARKED-FILES is the list of files that were marked `*'. + INSERTED-SUBDIRS is the list of subdirectores that were inserted. + HIDDEN-SUBDIRS is the list of inserted subdirs that were hidden. + SWITCHES is the string of `dired-listing-switches'. + +9. The following additional entries are used for a Gnus bookmark. + + (group . GNUS-GROUP-NAME) + (article . GNUS-ARTICLE-NUMBER) + (message-id . GNUS-MESSAGE-ID) + + GNUS-GROUP-NAME is the name of a Gnus group. + GNUS-ARTICLE-NUMBER is the number of a Gnus article. + GNUS-MESSAGE-ID is the identifier of a Gnus message. + +10. For a URL bookmark, FILENAME or LOCATION is a URL. + +11. A sequence bookmark has this additional entry: + + (sequence . COMPONENT-BOOKMARKS) + + COMPONENT-BOOKMARKS is the list of component bookmark names. + +12. A function bookmark has this additional entry, which records the +FUNCTION: + + (function . FUNCTION) + +13. A bookmark-list bookmark has this additional entry, which records +the state of buffer `*Bookmark List*' at the time it is created: + + (bookmark-list . STATE) + + STATE records the sort order, filter function, omit list, and title.") + +;;(@* "Compatibility Code for Older Emacs Versions") +;;; Compatibility Code for Older Emacs Versions ---------------------- + +(when (< emacs-major-version 23) + + ;; These definitions are for Emacs versions prior to Emacs 23. + ;; They are the same as the vanilla Emacs 24+ definitions, except as noted. + ;; They let older versions of Emacs handle bookmarks created with Emacs 23+. + ;; (Emacs < 23 also needs a compatible `bookmark-make-record' version, + ;; but I redefine it for all versions, in any case.) + + (defun Info-bookmark-make-record () + "Create a bookmark record for the current Info node (and point). +Implements `bookmark-make-record-function' for Info nodes." + (let* ((file (and (stringp Info-current-file) (file-name-nondirectory Info-current-file))) + (bookmark-name (if file + (concat "(" file ") " Info-current-node) + Info-current-node)) + (defaults (delq nil (list bookmark-name file Info-current-node)))) + `(,bookmark-name + ,@(bookmark-make-record-default 'NO-FILE) + (filename . ,Info-current-file) + (info-node . ,Info-current-node) + (handler . Info-bookmark-jump) + (defaults . ,defaults)))) + + (add-hook 'Info-mode-hook (lambda () (set (make-local-variable 'bookmark-make-record-function) + 'Info-bookmark-make-record))) + + (defvar bookmark-make-record-function 'bookmark-make-record-default + "Function called with no arguments, to create a bookmark record. +Modes can set this buffer-locally to enable bookmarking of locations +that should be treated specially for the mode. Global commands can +bind this and then create a bookmark, to get special treatment +anywhere. + +The function value should return a new bookmark record, which should +be a cons cell of the form (NAME . ALIST) or just ALIST, where ALIST +is as described in `bookmark-alist'. If it cannot construct the +record, then it should raise an error. + +NAME is a string that names the new bookmark. NAME can be nil, in +which case a default name is used. + +ALIST can contain an entry (handler . FUNCTION) which sets the handler +to FUNCTION, which is then used instead of `bookmark-default-handler'. +FUNCTION must accept the same arguments as `bookmark-default-handler'.") + + (defun bookmark-prop-get (bookmark prop) + "Return entry (property) PROP of BOOKMARK, or nil if no such entry. +BOOKMARK is a bookmark name or a bookmark record." + (cdr (assq prop (bmkp-bookmark-data-from-record bookmark)))) + + (defun bookmark-get-handler (bookmark) + "Return the `handler' entry for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (bookmark-prop-get bookmark 'handler)) + + (defun bookmark-jump-noselect (bookmark) + "Return the location recorded for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +The return value has the form (BUFFER . POINT), where BUFFER is a +buffer and POINT is the location within BUFFER." + (save-excursion (bookmark-handle-bookmark bookmark) (cons (current-buffer) (point))))) + +(when (< emacs-major-version 22) + + ;; These definitions are for Emacs versions prior to Emacs 22. + ;; They are the same as the vanilla Emacs 22+ definitions, except as noted. + +;;; ;; Bookmark+ doesn't use this, but `bookmark.el' still does. Who has a slow `baud-rate' now? +;;; (defun bookmark-maybe-message (fmt &rest args) +;;; "Apply `message' to FMT and ARGS, but only if the display is fast enough." +;;; (when (>= baud-rate 9600) (apply 'message fmt args))) + + ;; Emacs 22+ just uses `bookmark-jump-other-window' for the menu also. + (defun bmkp-menu-jump-other-window (event) + "Jump to BOOKMARK (a point in some file) in another window. +See `bookmark-jump-other-window'." + (interactive "e") + (bookmark-popup-menu-and-apply-function 'bookmark-jump-other-window + "Jump to Bookmark (Other Window)" event))) + +;;(@* "Core Replacements (`bookmark-*' except `bookmark-bmenu-*')") +;;; Core Replacements (`bookmark-*' except `bookmark-bmenu-*') ------- + + + +;; REPLACES DOCUMENTATION of ORIGINAL in `bookmark.el'. +;; +;; Doc now just says that this option is ignored by Bookmark+. +(put 'bookmark-sort-flag 'variable-documentation + "Ignored by Bookmark+, which uses option `bmkp-sort-comparer' instead.") + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Changed default value to t. +;; Added `:tag' strings for clarity. +;; Doc string says that it applies to all Bookmark+ files, and recommends that you back up your files. +;; +(defcustom bookmark-version-control t + "Whether to make numbered backups of your bookmarking files. +This includes bookmark files such as `bookmark-default-file' and also +Bookmark+ files `bmkp-bmenu-commands-file' and +`bmkp-bmenu-state-file'. + +The option can have value `nospecial', `t', `nil', or `never' . Value +`nospecial' means to use the `version-control' value. The others have +the same meanings as for option `version-control'. + +Use value `t' if your bookmarks are important to you. Consider also +using numeric backups. See also nodes `Backup Names' and `Backup +Deletion' in the Emacs manual." + :type '(choice :tag "When to make numbered backups" + (const :tag "Use value of option `version-control'" nospecial) + (const :tag "Never" never) + (const :tag "If existing already" nil) + (other :tag "Always" t)) + :group 'bookmark :group 'bookmark-plus) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Added value `edit'. +;; +(defcustom bookmark-automatically-show-annotations t + "*Non-nil means show annotations when jumping to a bookmark. +If the value is `edit' then open the annotation buffer in edit mode. + This has the same effect as using command `bookmark-edit-annotation'. +Any other non-nil value opens it in read-only mode. + This has the same effect as using command `bookmark-show-annotation'." + :type '(choice + (const :tag "Show annotation read-only" t) + (const :tag "Edit annotation" edit) + (const :tag "Do not show annotation automatically" nil)) + :group 'bookmark :group 'bookmark-plus) + + +(when (< emacs-major-version 23) + + + ;; REPLACES ORIGINAL in `bookmark.el' (Emacs 20-22). + ;; + ;; Same as Emacs 23+ version of the function. + ;; But the behavior is different from vanilla Emacs, because of the different `bookmark-get-bookmark' + ;; behavior: Only if BOOKMARK is a name without that property is it looked up in `bookmark-alist'. + ;; + (defun bookmark-get-bookmark-record (bookmark) + "Return the data part of BOOKMARK, that is, all but the name. +BOOKMARK is a bookmark name or a bookmark record. + +If it is a name with text property `bmkp-full-record', or if it is a +bookmark record, then it is NOT looked up in `bookmark-alist' (it need +not belong). Only if it is a name without that property is it looked +up in `bookmark-alist'." + (let ((data (cdr (bookmark-get-bookmark bookmark)))) + ;; A bookmark record is either (NAME ALIST) or (NAME . ALIST). + (if (and (null (cdr data)) (consp (caar data))) + (car data) + data))) + ) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; If BOOKMARK is a bookmark-name string that has non-nil property `bmkp-full-record' then just return that. +;; Only if BOOKMARK is a name without that property is it looked up in `bookmark-alist'. +;; +(defun bookmark-get-bookmark (bookmark &optional noerror) + "Return the full bookmark (record) that corresponds to BOOKMARK. +This is just `bmkp-get-bookmark' with non-nil NO-NAME-CHECK-P. + +If bookmark is a name with text property `bmkp-full-record', or if it +is a bookmark record, then it is NOT looked up in `bookmark-alist' (it +need not belong). Only if it is a name without that property is it +looked up in `bookmark-alist'. The vanilla Emacs version of this +function always looks up a string BOOKMARK in `bookmark-alist'. + +If you want to ensure that BOOKMARK is in `bookmark-alist' even when +BOOKMARK is a string, then use `bmkp-get-bookmark-in-alist', not +`bookmark-get-bookmark' or `bmkp-get-bookmark'." + (bmkp-get-bookmark bookmark noerror 'NO-NAME-CHECK-P)) + + +;; This is like vanilla `bookmark-get-bookmark' in `bookmark.el', but it has these differences: +;; +;; 1. If BOOKMARK is a bookmark-name string that has non-nil property `bmkp-full-record' +;; then return the value of that property - do not look up the string in `bookmark-alist'. +;; 2. Handle the should-not-happen case of non-string, non-cons. +;; 3. Added optional arg NO-NAME-CHECK-P. +;; 4. Unless NO-NAME-CHECK-P, to be valid when a cons, the car must be a string. +;; +(defun bmkp-get-bookmark (bookmark &optional noerror no-name-check-p) + "Return the full bookmark (record) that corresponds to BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. + +This function is like vanilla function `bookmark-get-bookmark', except +for these differences: + +1. If BOOKMARK is a bookmark name instead of a full bookmark then + return what `bmkp-bookmark-record-from-name' (with no MEMP check) + returns. That is, if the name has non-nil text property + `bmkp-full-record' then use that, without looking up the string in + `bookmark-alist'. + +2. By default, to be considered a valid bookmark record, it must have + a name. That is, as a cons, its car must be a string. + +3. Accepts optional arg NO-NAME-CHECK-P. + +Non-nil optional arg NOERROR means return nil if BOOKMARK is not a +valid bookmark. If NOERROR is nil then raise an error in this case. + +Non-nil optional arg NO-NAME-CHECK-P means don't require that the +bookmark have a name when checking for a valid bookmark. That is, +don't require that a cons bookmark have a string car. Use this arg if +you generally want the behavior of `bookmark-get-bookmark' but you +also want the other advantages of `bmkp-get-bookmark'. + +You can use this in place of `bookmark-get-bookmark' and remain +compatible with vanilla Emacs, if you do either of the following: + +* Use non-nil NOERROR. +* Use nil ERROR and non-nil NO-NAME-CHECK-P. + +In those cases you still take advantage of a BOOKMARK that has a name +with a `bmkp-full-record' property, but there's no requirement that +BOOKMARK have a name. + +This function is like `bmkp-get-bookmark-in-alist', except that +`bmkp-get-bookmark-in-alist' always tests whether BOOKMARK is in +`bookmark-alist', regardless of whether BOOKMARK is a string (a +bookmark name) or a full bookmark. `bmkp-get-bookmark-in-alist' is +thus a real test for bookmark existence. Use `bmkp-get-bookmark' only +when you do NOT want to look up the bookmark in `bookmark-alist'." + ;; Non-nil NO-NAME-CHECK-P means this, like `bookmark-get-bookmark', checks only for a cons. + ;; With nil NO-NAME-CHECK-P, the check is for a cons with a string car. We test for the string (the + ;; bookmark name) so that we can distinguish, for example, a list of bookmarks from a single bookmark. + (cond ((and (consp bookmark) (or no-name-check-p (stringp (car bookmark)))) ; No test of alist membership. + bookmark) + ((stringp bookmark) ; No MEMP check. + (bmkp-bookmark-record-from-name bookmark noerror)) + (t (and (not noerror) ; Return nil if NOERROR. + (error "Invalid bookmark: `%s'" bookmark))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Use option `bmkp-new-bookmark-default-names' to obtain the default name. +;; +(defun bookmark-make-record () + "Return a new bookmark record (NAME . ALIST) for the current location. +Start with `bookmark-make-record-function'. If it does not provide a +bookmark name, then use option `bmkp-new-bookmark-default-names' to +provide it. If that does not provide it then use +`bookmark-current-bookmark' or `bookmark-buffer-name', in that order." + (let ((record (funcall bookmark-make-record-function)) + defname) + (if (stringp (car record)) + record + (when (car record) (push nil record)) + (setq defname (catch 'bookmark-make-record + (dolist (fn bmkp-new-bookmark-default-names) + (when (functionp fn) ; Be sure it is defined and is a function. + (let ((val (funcall fn))) + (when (and (stringp val) (not (string= "" val))) + (throw 'bookmark-make-record val))))) + (or bookmark-current-bookmark (bookmark-buffer-name)))) + (when (and defname (not (stringp defname))) (setq defname (format "%s" defname))) ; Just in case. + (when (string= "" defname) (setq defname "")) ; You never know. + (setcar record defname) + record))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional args NO-REFRESH-P and NO-MSG-P. +;; 2. Update the bookmark name also, not just the data, for an existing bookmark. +;; 3. Use `bmkp-get-bookmark-in-alist' to test whether the bookmark already exists. +;; 4. Put full bookmark record on bookmark name (inside record) as property `bmkp-full-record'. +;; 5. Use `bmkp-maybe-save-bookmarks'. +;; 6. Add the bookmark to `bmkp-modified-bookmarks', and to `bmkp-automatic-bookmarks' if appropriate. +;; 7. Use `bmkp-refresh/rebuild-menu-list', not `bookmark-bmenu-surreptitiously-rebuild-list'. +;; 8. Return the bookmark. +;; +(defun bookmark-store (bookmark-name data no-overwrite &optional no-refresh-p no-msg-p) + "Store the bookmark named BOOKMARK-NAME, giving it DATA. +Return the new bookmark. + +DATA is the bookmark record without its name, i.e., what +`bmkp-bookmark-data-from-record' returns. + +If NO-OVERWRITE is non-nil and bookmark BOOKMARK-NAME already exists +in the current bookmark list (`bookmark-alist') then record the new +bookmark but do not discard the old one. The check for existence uses +`bmkp-get-bookmark-in-alist'. + +Non-nil optional arg NO-REFRESH-P means do not refresh/rebuild the +bookmark-list display. + +Non-nil optional arg NO-MSG-P means do not show progress messages. + +Note: In spite of the function name, like all functions that define or +change bookmarks, this function does not necessarily save your +bookmark file. Saving the file depends on `bookmark-save-flag'." + (bookmark-maybe-load-default-file) + (let ((bname (copy-sequence bookmark-name)) + bmk) + (unless (featurep 'xemacs) + ;; XEmacs's `set-text-properties' does not work on free-standing strings, apparently. + (set-text-properties 0 (length bname) () bname)) + (if (or no-overwrite (not (setq bmk (bmkp-get-bookmark-in-alist bname 'NOERROR)))) + (push (setq bmk (cons bname data)) bookmark-alist) ; Add new bookmark. + (bookmark-set-name bmk bname) ; Overwrite existing bookmark. + (setcdr bmk data)) + ;; Put the full bookmark on its name as property `bmkp-full-record'. + ;; Do this regardless of Emacs version and `bmkp-propertize-bookmark-names-flag'. + ;; If it needs to be stripped, that will be done when saving. + (put-text-property 0 (length bname) 'bmkp-full-record bmk bname) + (bmkp-maybe-save-bookmarks) + ;; These two are the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bmk bmkp-modified-bookmarks) + (setq bmkp-modified-bookmarks (cons bmk bmkp-modified-bookmarks))) + (when (and (boundp 'bmkp-setting-automatic-bmk-p) + (not (memq bmk bmkp-automatic-bookmarks))) + (setq bmkp-automatic-bookmarks (cons bmk bmkp-automatic-bookmarks))) + (setq bookmark-current-bookmark bname) + (unless no-refresh-p (bmkp-refresh/rebuild-menu-list bmk no-msg-p)) + bmk)) ; Return the bookmark. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Mention `C-c C-M-c', not `C-c C-c'. +;; +;;;###autoload (autoload 'bookmark-default-annotation-text "bookmark+") +(defun bookmark-default-annotation-text (bookmark-name) + "Return default annotation text for BOOKMARK-NAME. +The default annotation text is simply some text explaining how to use +annotations." + (concat "# Type the annotation for bookmark `" bookmark-name "' here.\n" + "# All lines that start with a `#' will be deleted.\n" + "# Type `C-c C-M-c' when done.\n#\n" + "# Author: " (user-full-name) " <" (user-login-name) "@" + (system-name) ">\n" + "# Date: " (current-time-string) "\n")) + + +;; REPLACES ORIGINAL in `bookmark.el' (Emacs 24.4+). +;; +;; Usable for older Emacs versions also. +;; +;;;###autoload (autoload 'bookmark-insert-annotation "bookmark+") +(defun bookmark-insert-annotation (bookmark) + "Insert annotation for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (setq bookmark (bmkp-bookmark-name-from-record (bmkp-get-bookmark-in-alist bookmark))) + (insert (funcall (if (boundp 'bookmark-edit-annotation-text-func) + bookmark-edit-annotation-text-func + bookmark-read-annotation-text-func) + bookmark)) + (let ((annotation (bookmark-get-annotation bookmark))) + (when (and annotation (not (string-equal annotation ""))) (insert annotation)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Derive from value of option `bmkp-annotation-modes-inherit-from'. +;; 2. First, remove parent map from `bookmark-edit-annotation-mode-map', so it is derived anew. +;; 3. Corrected typo in doc string: *send-EDITED-*. +;; 4. Need to use `eval', to pick up option value and reset parent keymap. +;; 5. Bind `C-x C-q' to `bmkp-show-this-annotation-read-only'. +;; +;;;###autoload (autoload 'bookmark-edit-annotation-mode "bookmark+") +(eval + `(progn + ;; Get rid of default parent, so `bmkp-annotation-modes-inherit-from' is used for the map. + (when (keymapp bookmark-edit-annotation-mode-map) + (set-keymap-parent bookmark-edit-annotation-mode-map nil)) + (define-derived-mode bookmark-edit-annotation-mode ,bmkp-annotation-modes-inherit-from + "Edit Bookmark Annotation" + "Mode for editing the annotation of a bookmark. +When you have finished composing, use `C-c C-M-c'. + +\\{bookmark-edit-annotation-mode-map}") + (define-key bookmark-edit-annotation-mode-map "\C-x\C-q" 'bmkp-show-this-annotation-read-only) + ;; Define this key because Org mode co-opts `C-c C-c' as a prefix key. + (define-key bookmark-edit-annotation-mode-map "\C-c\C-\M-c" 'bookmark-send-edited-annotation))) + +(define-derived-mode bookmark-show-annotation-mode bookmark-edit-annotation-mode + "Show Bookmark Annotation" + "Mode for displaying the annotation of a bookmark. + +\\{bookmark-show-annotation-mode-map}" + (setq buffer-read-only t) + (define-key bookmark-show-annotation-mode-map "\C-x\C-q" 'bmkp-edit-this-annotation)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Record an empty annotation as nil, not "". +;; 2. BUG fix: Put point back where it was (on the bookmark just annotated). +;; 3. Refresh menu list, to pick up the `a' marker. +;; 4. Make sure it's the annotation buffer that gets killed. +;; 5. Delete window also, if `misc-cmds.el' loaded. +;; +;;;###autoload (autoload 'bookmark-send-edited-annotation "bookmark+") +(defun bookmark-send-edited-annotation () ; Bound to `C-c C-M-c' in `bookmark-edit-annotation-mode'. + "Use buffer contents as annotation for a bookmark. +Lines beginning with `#' are ignored." + (interactive) + (unless (derived-mode-p 'bookmark-edit-annotation-mode) + (error "Not in mode derived from `bookmark-edit-annotation-mode'")) + (goto-char (point-min)) + (while (< (point) (point-max)) (if (= (following-char) ?#) (bookmark-kill-line t) (forward-line 1))) + (let ((annotation (buffer-substring-no-properties (point-min) (point-max))) + (bookmark bookmark-annotation-name) + (annotation-buf (current-buffer))) + (when (string= annotation "") (setq annotation nil)) + (bookmark-set-annotation bookmark annotation) + (setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count)) + (bmkp-refresh/rebuild-menu-list bookmark) ; So display `a' and `*' markers (updated). + (if (fboundp 'kill-buffer-and-its-windows) + (kill-buffer-and-its-windows annotation-buf) ; Defined in `misc-cmds.el'. + (kill-buffer annotation-buf)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Make it a command (added `interactive' spec). Prefix arg means add or edit (choose any bookmark). +;; 2. Manage buffer-modified-p. +;; 3. Emacs 26+: Added ignored &rest arg to accommodate vanilla Emacs fix to bug #20150 (not a bug for us). +;; +;;;###autoload (autoload 'bookmark-edit-annotation "bookmark+") +(defun bookmark-edit-annotation (bookmark &rest _IGNORED) ; Bound to `C-x x a e' + "Pop up a buffer for editing bookmark BOOKMARK's annotation. +Interactively, you are prompted for the bookmark name. With a prefix +arg, you can choose any bookmark. Otherwise, only annotated bookmarks +are candidates. + +Non-interactively, BOOKMARK is a bookmark name or a bookmark record." + (interactive + (let ((alist (bmkp-annotated-alist-only))) + (list (bookmark-completing-read (format "%s annotation for bookmark" + (if current-prefix-arg "Add or edit" "Edit")) + (bmkp-default-bookmark-name alist) + alist + nil + nil + (not current-prefix-arg))))) + (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*")) + (bookmark-insert-annotation bookmark) + (bookmark-edit-annotation-mode) + (setq bookmark-annotation-name bookmark)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Added optional arg ALIST. +;; +(defun bookmark-all-names (&optional alist) + "Return a list of all bookmark names. +The names are those of the bookmarks in ALIST or, if nil, +`bookmark-alist'." + (bookmark-maybe-load-default-file) + (mapcar (lambda (bmk) (bmkp-bookmark-name-from-record bmk)) (or alist bookmark-alist))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional args ALIST, PRED, and HIST. +;; 2. Use helper function `bmkp-completing-read-1', which does this: +;; (a) binds `icicle-delete-candidate-object' to (essentially) `bookmark-delete'. +;; (b) forces you to enter a non-empty name, if DEFAULT is nil or "". +;; +(defun bookmark-completing-read (prompt &optional default alist pred hist use-nil-alist-p) + "Read a bookmark name, prompting with PROMPT. +PROMPT is automatically suffixed with \": \", so do not include that. + +DEFAULT is a string or a list of strings. If the user input is empty +then return the string (or the first string in the list). If DEFAULT +is nil (absent) then return \"\" for empty input. + +The bookmark alist argument used for completion is optional arg ALIST. +If USE-NIL-ALIST-P is nil, then ALIST defaults to `bookmark-alist'. + +Optional arg PRED is a predicate used for completion. + +Optional arg HIST is a history variable for completion. Default is + `bookmark-history'. + +Non-nil optional arg USE-NIL-ALIST-P means do not default ALIST to +`bookmark-alist': if ALIST is nil then there are no bookmark +candidates. + +If you access this function from a menu, then, depending on the value +of option `bmkp-menu-popup-max-length' and the number of +bookmarks in ALIST, you choose the bookmark using a menu or using +completion. + +If you use Icicles, then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate." + (bmkp-completing-read-1 prompt default alist pred hist nil use-nil-alist-p)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Handles also regions and non-file buffers. +;; 2. Do not use NO-CONTEXT or POSN if < Emacs 24. +;; +(defun bookmark-make-record-default (&optional no-file no-context position visits no-region) + "Return the record describing the location of a new bookmark. +Point must be where the bookmark is to be set. + +Non-nil NO-FILE means return only the subset of the record that + pertains to the location within the buffer (not also the file name). + +Non-nil NO-CONTEXT means do not include the front and rear context +strings in the record enough. + +Non-nil POSITION means record it, not point, as the `position' entry. + +Non-nil VISITS means record it as the `visits' entry. + +Non-nil NO-REGION means do not include the region end, `end-position'." + (unless (> emacs-major-version 23) (setq no-context nil)) + (let* ((dired-p (and (boundp 'dired-buffers) (car (rassq (current-buffer) dired-buffers)))) + (buf (buffer-name)) + (ctime (current-time)) + + ;; Begin `let*' dependencies. + (regionp (and transient-mark-mode mark-active (> (region-end) (region-beginning)))) + (beg (if regionp (region-beginning) (or position (point)))) + (end (if regionp (region-end) (point))) + (fcs (and (not no-context) (if regionp + (bmkp-position-post-context-region beg end) + (bmkp-position-post-context beg)))) + (rcs (and (not no-context) (if regionp + (bmkp-position-pre-context-region beg) + (bmkp-position-pre-context beg)))) + (fcrs (and (not no-context) regionp (bmkp-end-position-pre-context beg end))) + (ecrs (and (not no-context) regionp (bmkp-end-position-post-context end)))) + `(,@(unless no-file + `((filename . ,(cond ((buffer-file-name) (bookmark-buffer-file-name)) + (dired-p nil) + (t bmkp-non-file-filename))))) + (buffer-name . ,buf) + ,@(unless no-context `((front-context-string . ,fcs))) + ,@(unless no-context `((rear-context-string . ,rcs))) + ,@(unless no-context `((front-context-region-string . ,fcrs))) + ,@(unless no-context `((rear-context-region-string . ,ecrs))) + (visits . ,(or visits 0)) + (time . ,ctime) + (created . ,ctime) + (position . ,beg) + ,@(when (and regionp (not no-region)) `((end-position . ,end)))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Unless non-nil arg DO-NOT-PROPERTIZE-P, put full bookmark record on bookmark name (inside record), +;; as property `bmkp-full-record'. +;; +(defun bookmark-alist-from-buffer (&optional do-not-propertize-p) + "Read and return a bookmark list (in any format) from the current buffer. +Unless optional arg DO-NOT-PROPERTIZE-P is non-nil, put the full +bookmark record on the bookmark name (in the record), as a text +property. Point is irrelevant and unaffected." + (let ((bmks (save-excursion + (goto-char (point-min)) + (if (search-forward bookmark-end-of-version-stamp-marker nil t) + (condition-case err + (read (current-buffer)) + (error (error "Cannot read definitions in bookmark file: %s" + (error-message-string err)))) + ;; Else we're dealing with format version 0 + (if (search-forward "(" nil t) + (progn (forward-char -1) + (condition-case err + (read (current-buffer)) + (error (error "Cannot read definitions in bookmark file: %s" + (error-message-string err))))) + ;; Else no hope of getting information here. + (error "Buffer is not in bookmark-list format")))))) + ;; Put full bookmark on bookmark names as property `bmkp-full-record'. + ;; Do this regardless of Emacs version and `bmkp-propertize-bookmark-names-flag'. + ;; If property needs to be stripped, that will be done when saving. + (unless do-not-propertize-p + (let (bname) + (dolist (bmk bmks) + (setq bname (bmkp-bookmark-name-from-record bmk)) + (put-text-property 0 (length bname) 'bmkp-full-record bmk bname)))) + bmks)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Use `bookmark-make-record'. +;; 2. Use special default prompts for active region, EWW, W3M, and Gnus. +;; 3. Use function `bmkp-new-bookmark-default-names', in addition to the name that +;; `bookmark-make-record' comes up with, as the list of default values. +;; 4. Use `bmkp-completing-read-lax', choosing from current buffer's bookmarks. +;; 5. Numeric prefix arg (diff from plain): all bookmarks as completion candidates. +;; 6. Ask for confirmation if (a) not plain `C-u' and (b) NAME names an existing bookmark. +;; 7. Do not overwrite properties listed in option `bmkp-properties-to-keep'. +;; 8. Added optional args INTERACTIVEP and NO-REFRESH-P. +;; 9. Prompt for tags if `bmkp-prompt-for-tags-flag' is non-nil. +;; 10. Possibly highlight bookmark and other bookmarks in buffer, per `bmkp-auto-light-when-set'. +;; 11. Make bookmark temporary, if `bmkp-autotemp-bookmark-predicates' says to. +;; 12. Run `bmkp-after-set-hook'. +;; +;;;###autoload (autoload 'bookmark-set "bookmark+") +(defun bookmark-set (&optional name parg interactivep no-refresh-p) ; `C-x r M', `C-x x c M' + "Set a bookmark named NAME, then run `bmkp-after-set-hook'. +If the region is active (`transient-mark-mode') and nonempty, then +record the region limits in the bookmark. + +If NAME is nil, then prompt for the bookmark name. The default names +for prompting are as follows (in order of priority): + + * If in W3M mode, then the current W3M title. + + * If in a Gnus mode, then the Gnus summary article header. + + * If on a `man' page, then the page name (command and section). + + * If the region is active and nonempty, then the buffer name followed + by \": \" and the region prefix (up to + `bmkp-bookmark-name-length-max' chars). + + * The names defined by option `bmkp-new-bookmark-default-names'. + + * The value of variable `bookmark-current-bookmark', the name of the + last-used bookmark for the current file. + + * The value returned by function `bookmark-buffer-name'. + +For Emacs 23+, all of the names described above are available as +default values, by repeating `M-n'. For older Emacs versions, the +first name provided is the only default value. + +While entering a bookmark name at the prompt: + + * You can use (lax) completion against bookmarks in the same buffer. + If there are no bookmarks in the current buffer, then all bookmarks + are completion candidates. (See also below, about a numeric prefix + argument.) + + * You can use `C-M-w' to yank words from the buffer to the + minibuffer. Repeating `C-M-w' yanks successive words (newlines + between yanked words are stripped out). + + * You can use `C-M-u' to insert the name of the last bookmark used in + the buffer. This can be useful as an aid to track your progress + through a large file. (If no bookmark has yet been used, then + `C-M-u' inserts the name of the visited file.) + +A prefix argument changes the behavior as follows: + + * Numeric prefix arg: Use all bookmarks as completion candidates, + instead of just the bookmarks for the current buffer. + + * Plain prefix arg (`C-u'): Do not overwrite a bookmark that has the + same name as NAME, if such a bookmark already exists. Instead, + push the new bookmark onto the bookmark alist. + + For use by vanilla Emacs, only the most recently set bookmark named + NAME is in effect at any given time, but any others named NAME can + become available, should you decide to delete the most recent one. + + For Bookmark+, if option `bmkp-propertize-bookmark-names-flag' is + non-`nil' then you can use any number of bookmarks that have the + same name. If that option is `nil' then the behavior is the same + as for vanilla Emacs. + +Bookmark properties listed in option `bmkp-properties-to-keep' are not +overwritten when you set an existing bookmark. Their existing values +are kept. Other properties may be updated. Properties such as +`position' and `visit' are typically updated, for example, to record +the new position and the number of visits. + +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). + +From Lisp code: + +* Non-nil INTERACTIVEP means the user can be prompted for + confirmation, tags, etc., and it is used for the call to + `bookmark-store'. + +* Non-nil NO-REFRESH-P is also passed to `bookmark-store'. It means + do not refresh/rebuild the bookmark-list display." + (interactive (list nil current-prefix-arg t)) + (unwind-protect + (progn + (bookmark-maybe-load-default-file) + (setq bookmark-current-point (point)) ; `bookmark-current-point' is a free var here. + ;; Do not set these if they are already set in some other buffer (e.g gnus-art). + (unless (and bookmark-yank-point bookmark-current-buffer) + (save-excursion (skip-chars-forward " ") (setq bookmark-yank-point (point))) + (setq bookmark-current-buffer (current-buffer))) + (let* ((record (bookmark-make-record)) + (defname (cond ((and (eq major-mode 'eww-mode) + (fboundp 'bmkp-make-eww-record) ; Emacs 25+ + (bmkp-eww-title))) + ((eq major-mode 'w3m-mode) w3m-current-title) + ((eq major-mode 'gnus-summary-mode) (elt (gnus-summary-article-header) 1)) + ((memq major-mode '(Man-mode woman-mode)) + (buffer-substring (point-min) (save-excursion (goto-char (point-min)) + (skip-syntax-forward "^ ") + (point)))) + (t nil))) + (defname (and defname (bmkp-replace-regexp-in-string "\n" " " defname))) + (bname (or name (bmkp-completing-read-lax + "Set bookmark" + (bmkp-new-bookmark-default-names defname) + (and (or (not parg) (consp parg)) ; No numeric PARG: all bookmarks. + (bmkp-specific-buffers-alist-only)) + nil 'bookmark-history (or (not parg) (consp parg)))))) + ;; BNAME should not be "" now, since `bmkp-new-bookmark-default-names' should provide default(s) + ;; and empty input to `bmkp-completing-read-lax' returns the default. But just in case... + (when (and (string= bname "") defname) (setq bname defname)) + (while (string= "" bname) + (message "Enter a NON-EMPTY bookmark name") (sit-for 2) + (setq bname (bmkp-completing-read-lax + "Set bookmark" + (bmkp-new-bookmark-default-names defname) + (and (or (not parg) (consp parg)) ; No numeric PARG: all bookmarks. + (bmkp-specific-buffers-alist-only)) + nil 'bookmark-history (or (not parg) (consp parg))))) + (let ((old-bmk (bmkp-get-bookmark-in-alist bname 'NOERROR)) + old-prop) + (when (and interactivep bmkp-bookmark-set-confirms-overwrite-p (atom parg) old-bmk + (not (y-or-n-p (format "Overwrite bookmark `%s'? " bname)))) + (error "OK, canceled")) + (when old-bmk ; Restore props of existing bookmark per `bmkp-properties-to-keep'. + (dolist (prop bmkp-properties-to-keep) + (bookmark-prop-set record prop (bookmark-prop-get old-bmk prop))))) + ;; Maybe make bookmark temporary. + ;; Pass RECORD, not BNAME, so `bookmark-prop-set' DTRT in `bmkp-make-bookmark-temporary'. + (if bmkp-autotemp-all-when-set-p + (bmkp-make-bookmark-temporary record) + (catch 'bookmark-set + (dolist (pred bmkp-autotemp-bookmark-predicates) + (when (and (functionp pred) (funcall pred bname)) + (bmkp-make-bookmark-temporary record) + (throw 'bookmark-set t))))) + (bookmark-store bname (cdr record) (consp parg) no-refresh-p (not interactivep)) + (when (and interactivep bmkp-prompt-for-tags-flag) + (bmkp-add-tags bname (bmkp-read-tags-completing) 'NO-UPDATE-P)) ; Do not update here. + (case (and (boundp 'bmkp-auto-light-when-set) bmkp-auto-light-when-set) + (autonamed-bookmark (when (bmkp-autonamed-bookmark-p bname) + (bmkp-light-bookmark bname))) + (non-autonamed-bookmark (unless (bmkp-autonamed-bookmark-p bname) + (bmkp-light-bookmark bname))) + (any-bookmark (bmkp-light-bookmark bname)) + (autonamed-in-buffer (bmkp-light-bookmarks (bmkp-autonamed-this-buffer-alist-only) + nil interactivep)) + (non-autonamed-in-buffer (bmkp-light-bookmarks + (bmkp-remove-if #'bmkp-autonamed-this-buffer-bookmark-p + (bmkp-this-buffer-alist-only)) + nil interactivep)) + (all-in-buffer (bmkp-light-this-buffer nil interactivep))) + (run-hooks 'bmkp-after-set-hook) + (if bookmark-use-annotations + (bookmark-edit-annotation bname) + (goto-char bookmark-current-point)))) ; `bookmark-current-point' is a free var here. + (setq bookmark-yank-point nil + bookmark-current-buffer nil))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Put full bookmark record on the name as property `bmkp-full-record'. +;; 2. Add BOOKMARK to `bmkp-modified-bookmarks'. +;; 3. The different `bookmark-get-bookmark' behavior from vanilla Emacs means we can get the right bookmark +;; if it has a name with property `bmkp-full-record', without looking it up in `bookmark-alist'. +;; But we don't require that BOOKMARK have a name, so calls from vanilla or other code aren't bothered. +;; +(defun bookmark-set-name (bookmark newname) + "Set name of BOOKMARK to NEWNAME. +BOOKMARK is a bookmark name or a bookmark record. +Put the full bookmark on its name as property `bmkp-full-record'. +Add BOOKMARK to `bmkp-modified-bookmarks'. + +If BOOKMARK is a name with text property `bmkp-full-record', or if it +is a bookmark record, then it is NOT looked up in `bookmark-alist' (it +need not belong). If it is a name without that property then it is +looked up in `bookmark-alist'." + (setq bookmark (bookmark-get-bookmark bookmark)) + (setcar bookmark newname) + ;; Put the full bookmark on its name as property `bmkp-full-record'. + ;; Do this regardless of Emacs version and `bmkp-propertize-bookmark-names-flag'. + ;; If it needs to be stripped, that will be done when saving. + (put-text-property 0 (length newname) 'bmkp-full-record bookmark newname) + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bookmark bmkp-modified-bookmarks) + (setq bmkp-modified-bookmarks (cons bookmark bmkp-modified-bookmarks)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Prevent adding a newline in a bookmark name when yanking. +;; +;;;###autoload (autoload 'bookmark-yank-word "bookmark+") +(defun bookmark-yank-word () ; Bound to `C-M-w' in minibuffer when setting bookmark. + "Yank the word at point in `bookmark-current-buffer'. +Repeat to yank consecutive words from the current buffer, appending +them to the minibuffer. However, newline characters between yanked +words are stripped out." + (interactive) + (let ((string (with-current-buffer bookmark-current-buffer + (goto-char bookmark-yank-point) + (buffer-substring-no-properties (point) + (progn (forward-word 1) + (setq bookmark-yank-point (point))))))) + (setq string (bmkp-replace-regexp-in-string "\n" "" string)) + (insert string))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Separate renaming of obsolete default bookmark name (do it even if not loading the default file). +;; 2. Load `bmkp-last-as-first-bookmark-file' if it is non-nil. +;; +(defun bookmark-maybe-load-default-file () + "If bookmarks have not yet been loaded, load them. +If `bmkp-last-as-first-bookmark-file' is non-nil, load it. +Otherwise, load `bookmark-default-file'." + ;; If there is no file at `bookmark-default-file' but there is a file with the obsolete default + ;; name, then rename that file to the value of `bookmark-default-file'. + ;; Do this regardless of whether it is `bookmark-default-file' that we load here. + (when (and (file-exists-p bookmark-old-default-file) (not (file-exists-p bookmark-default-file))) + (rename-file bookmark-old-default-file bookmark-default-file)) + (let ((file-to-load (bmkp-default-bookmark-file))) + (and (not bookmarks-already-loaded) + (null bookmark-alist) + (file-readable-p file-to-load) + (bookmark-load file-to-load t 'nosave) + (setq bookmarks-already-loaded t)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Save DISPLAY-FUNCTION to `bmkp-jump-display-function' before calling `bookmark-handle-bookmark'. +;; 2. Update the name and position of an autonamed bookmark, in case it moved. +;; 3. Possibly highlight bookmark and other bookmarks in buffer, per `bmkp-auto-light-when-jump'. +;; 4. Added `catch', so a handler can throw to skip the rest of the processing if it wants. +;; +(defun bookmark--jump-via (bookmark display-function) + "Display BOOKMARK using DISPLAY-FUNCTION. +Then run `bookmark-after-jump-hook' and show annotations for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +DISPLAY-FUNCTION is as in `bookmark-jump'." + (bmkp-record-visit bookmark 'BATCHP) + (setq bmkp-jump-display-function display-function) + (catch 'bookmark--jump-via + (bookmark-handle-bookmark bookmark) + (unless (and bmkp-use-w32-browser-p (fboundp 'w32-browser) (bookmark-get-filename bookmark)) + (let ((win (get-buffer-window (current-buffer) 0))) + (when win (set-window-point win (point)))) + ;; If this is an autonamed bookmark, update its name and position, in case it moved. + ;; But don't do this if we're using w32, since we might not have moved to the bookmark position. + (when (and (bmkp-autonamed-bookmark-for-buffer-p bookmark (buffer-name)) + (not bmkp-use-w32-browser-p)) + (setq bookmark (bmkp-update-autonamed-bookmark bookmark))) + (case (and (boundp 'bmkp-auto-light-when-jump) bmkp-auto-light-when-jump) + (autonamed-bookmark (when (bmkp-autonamed-bookmark-p bookmark) + (bmkp-light-bookmark bookmark nil nil nil 'USE-POINT))) + (non-autonamed-bookmark (unless (bmkp-autonamed-bookmark-p bookmark) + (bmkp-light-bookmark bookmark nil nil nil 'USE-POINT))) + (any-bookmark (bmkp-light-bookmark bookmark nil nil nil 'USE-POINT)) + (autonamed-in-buffer (bmkp-light-bookmarks + (bmkp-remove-if-not #'bmkp-autonamed-bookmark-p + (bmkp-this-buffer-alist-only)) + nil 'MSG)) + (non-autonamed-in-buffer (bmkp-light-bookmarks (bmkp-remove-if #'bmkp-autonamed-bookmark-p + (bmkp-this-buffer-alist-only)) + nil 'MSG)) + (all-in-buffer (bmkp-light-this-buffer nil 'MSG)))) + (let ((orig-buff (current-buffer))) ; Used by `crosshairs-highlight'. + (run-hooks 'bookmark-after-jump-hook)) + (let ((jump-fn (bmkp-get-tag-value bookmark "bmkp-jump"))) + (when jump-fn (funcall jump-fn))) + (when bookmark-automatically-show-annotations (bookmark-show-annotation bookmark)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg REQUIRE-NAME-P. Pass it to `bmkp-get-bookmark'. +;; 2. Use `bmkp-get-bookmark' instead of `bookmark-get-bookmark', so we can get the right bookmark if +;; it has a name with property `bmkp-full-record'. But unless REQUIRE-NAME-P, don't require that BOOKMARK +;; have a name, so calls from vanilla or other code won't be bothered. +;; 3. Add to beginning, not end, of bookmark record. +;; 4. Do not use `nconc'. +;; 5. Respect both old and newer bookmark formats. +;; 6. Add BOOKMARK to `bmkp-modified-bookmarks'. +;; +(defun bookmark-prop-set (bookmark prop val &optional require-name-p) + "Set the entry (property) PROP of BOOKMARK to VAL. +BOOKMARK is a bookmark name or a bookmark record. +If it is a bookmark name then it is looked up in `bookmark-alist'. +If it is a record then it is NOT looked up (need not belong). +If it is or has a name that has non-nil property `bmkp-full-record', +then use the bookmark in `bookmark-alist' that is the value of that +property. (use `bmkp-get-bookmark', not `bookmark-get-bookmark'.)" + (let* ((bmk (bmkp-get-bookmark bookmark nil (not require-name-p))) + (cell (assq prop (bmkp-bookmark-data-from-record bmk)))) + (if cell + (setcdr cell val) + (setcdr bmk (if (consp (car (cadr bmk))) + (list (cons (cons prop val) (cadr bmk))) ; Old format: ("name" ((filename . "f")...)) + (cons (cons prop val) (cdr bmk))))) ; New format: ("name" (filename . "f")...) + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bmk bmkp-modified-bookmarks) + (setq bmkp-modified-bookmarks (cons bmk bmkp-modified-bookmarks))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg FLIP-USE-REGION-P. +;; 2. Use `bmkp-default-bookmark-name' as default when interactive. +;; 3. Use `bmkp-jump-1'. +;; 4. Added note about Icicles `S-delete' to doc string. +;; +;;;###autoload (autoload 'bookmark-jump "bookmark+") +(defun bookmark-jump (bookmark ; Bound to `C-x j j', `C-x r b', `C-x x g' + &optional display-function flip-use-region-p) + "Jump to 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 function `bookmark-load' for more about this. + +If the file pointed to by BOOKMARK no longer exists, you are asked if +you wish to give the bookmark a new location. If so, `bookmark-jump' +jumps to the new location and saves it. + +If the bookmark defines a region, then the region is activated if +`bmkp-use-region' is not-nil or it is nil and you use a prefix +argument. A prefix arg temporarily flips the value of +`bmkp-use-region'. + +If you use Icicles, then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate. + +In Lisp code: +BOOKMARK is a bookmark name or a bookmark record. +Non-nil DISPLAY-FUNCTION is a function to display the bookmark. By + default, use `pop-to-buffer-same-window'. +Non-nil FLIP-USE-REGION-P flips the value of `bmkp-use-region'." + (interactive (list (bookmark-completing-read "Jump to bookmark" (bmkp-default-bookmark-name)) + nil + current-prefix-arg)) + (bmkp-jump-1 bookmark (or display-function 'bmkp--pop-to-buffer-same-window) flip-use-region-p)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg FLIP-USE-REGION-P. +;; 2. Use `bmkp-default-bookmark-name' as default when interactive. +;; 3. Use `bmkp-jump-1'. +;; +;;;###autoload (autoload 'bookmark-jump-other-window "bookmark+") +(defun bookmark-jump-other-window (bookmark &optional flip-use-region-p) + ; Bound to `C-x 4 j j', `C-x x j', `C-x x o', `C-x x q' + "Jump to bookmark BOOKMARK in another window. +See `bookmark-jump', in particular for info about using a prefix arg." + (interactive (list (bookmark-completing-read "Jump to bookmark (in another window)" + (bmkp-default-bookmark-name)) + current-prefix-arg)) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + + +;; REPLACES ORIGINAL in `bookmark.el' (Emacs 27+) +;; +;; 1. Added optional arg FLIP-USE-REGION-P. +;; 2. Use `bmkp-default-bookmark-name' as default when interactive. +;; 3. Use `bmkp-jump-1'. +;; +;;;###autoload (autoload 'bookmark-jump-other-frame "bookmark+") +(defun bookmark-jump-other-frame (bookmark &optional flip-use-region-p) ; Bound to `C-x 5 B' + "Jump to bookmark BOOKMARK in another frame. +See `bookmark-jump', in particular for info about using a prefix arg." + (interactive (list (bookmark-completing-read "Jump to bookmark (in another frame)" + (bmkp-default-bookmark-name)) + current-prefix-arg)) + (let ((pop-up-frames t)) (bookmark-jump-other-window bookmark flip-use-region-p))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Invoke MS Windows `Open' action if `bmkp-use-w32-browser-p' and if `w32-browser' is defined. +;; 2. Favor entry `file-handler' over entry `handler'. If the former is available, apply it to the file. +;; 3. If BOOKMARK has its own handler but that is not a defined function, then use the default handler. +;; This lets Emacs 22, for instance, handle Emacs 23+ image bookmarks. +;; 4. Different relocation message for non-file bookmark. +;; +(defun bookmark-handle-bookmark (bookmark) + "Call BOOKMARK's handler, or `bookmark-default-handler' if it has none. +Return nil or raise an error. + +BOOKMARK is a bookmark name or a bookmark record. + +More precisely: + + If `bmkp-use-w32-browser-p' is non-`nil' and `w32-browser' is + defined then invoke the MS Windows `Open' action. + + Else, if BOOKMARK has both `file-handler' and `filename' entries + then apply the former to the latter. + + Else, if BOOKMARK has a `handler' entry whose value is a defined + function then apply it to BOOKMARK. + + Else, apply the default bookmark handler, + `bookmark-default-handler', to BOOKMARK. + +The default handler changes the current buffer and point. + +If the default handler is used and a file error is raised, the error +is handled as follows: + If BOOKMARK has no `filename' entry, do nothing. + Else prompt to relocate the file. + If relocated, then try again to handle. Else raise a file error." + (cond ((and bmkp-use-w32-browser-p (fboundp 'w32-browser) (bookmark-get-filename bookmark)) + (w32-browser (bookmark-get-filename bookmark)) + ;; This `throw' is only for the case where this handler is called from `bookmark--jump-via'. + ;; It tells `bookmark--jump-via' to skip the rest of what it does after calling the handler. + (condition-case nil (throw 'bookmark--jump-via 'BOOKMARK-HANDLE-BOOKMARK) (no-catch nil))) + ((functionp (bookmark-prop-get bookmark 'file-handler)) + (funcall (bookmark-prop-get bookmark 'file-handler) (bookmark-get-filename bookmark))) + ((functionp (bookmark-get-handler bookmark)) + (funcall (bookmark-get-handler bookmark) (bmkp-get-bookmark bookmark))) + (t + (condition-case err + (funcall 'bookmark-default-handler (bmkp-get-bookmark bookmark)) + (bookmark-error-no-filename ; `file-error' + ;; BOOKMARK can be either a bookmark name or a bookmark record. + ;; If a record, do nothing - assume it is a bookmark used internally by some other package. + (when (stringp bookmark) + (let ((file (bookmark-get-filename bookmark)) + (use-dialog-box nil) + (use-file-dialog nil)) + (when file + ;; Ask user whether to relocate the file. If no, signal the file error. + (unless (string= file bmkp-non-file-filename) (setq file (expand-file-name file))) + (ding) + (cond ((y-or-n-p (if (and (string= file bmkp-non-file-filename) + (bmkp-get-buffer-name bookmark)) + "Bookmark's buffer does not exist. Re-create it? " + (concat (file-name-nondirectory file) " nonexistent. Relocate \"" + bookmark "\"? "))) + (if (string= file bmkp-non-file-filename) + ;; This is probably not the right way to get the correct buffer, but it's + ;; better than nothing, and it gives the user a chance to DTRT. + (pop-to-buffer (bmkp-get-buffer-name bookmark)) ; Create buffer. + (bookmark-relocate bookmark)) ; Relocate to file. + (funcall (or (bookmark-get-handler bookmark) 'bookmark-default-handler) + (bmkp-get-bookmark bookmark))) ; Try again + (t + (message "Bookmark not relocated: `%s'" bookmark) + (signal (car err) (cdr err))))))))))) + (when (stringp bookmark) (setq bookmark-current-bookmark bookmark)) + ;; $$$$$$ The vanilla code returns nil, but there is no explanation of why and no code seems + ;; to use the return value. Perhaps we should return the bookmark instead? + nil) ; Return nil if no error. + +(put 'bookmark-error-no-filename 'error-conditions + '(error bookmark-errors bookmark-error-no-filename)) +(put 'bookmark-error-no-filename 'error-message "Bookmark has no associated file (or directory)") + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Use `bmkp-get-bookmark' instead of `bookmark-get-bookmark', so we can get the right bookmark if +;; it has a name with property `bmkp-full-record'. +;; 2. Support regions, buffer names, and entry `file-handler'. +;; 3. Handle MS Windows `Open' command if `bmkp-use-w32-browser-p' and if `w32-browser' is defined. +;; +(defun bookmark-default-handler (bookmark) + "Default handler to jump to the location of BOOKMARK. +Return nil (or raise an error). + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'. + +If `bmkp-use-w32-browser-p' is non-nil and function `w32-browser' is +defined, then call `w32-browser'. That is, use the default MS Windows +application for the bookmarked file. + +If BOOKMARK has entries `file-handler' and `filename', then apply the +value of the former to the latter. + +If BOOKMARK is an old-style Info bookmark, then go to the Info node. + +If BOOKMARK records a nonempty region and `bmkp-use-region' is + non-nil then activate the region. + +Otherwise, call `bmkp-goto-position' to go to the recorded position." + (let* ((bmk (bmkp-get-bookmark bookmark)) + (file (bookmark-get-filename bmk)) + (buf (bookmark-prop-get bmk 'buffer)) + (bufname (bmkp-get-buffer-name bmk)) + (pos (bookmark-get-position bmk)) + (end-pos (bmkp-get-end-position bmk)) + (old-info-node (and (not (bookmark-get-handler bookmark)) (bookmark-prop-get bmk 'info-node)))) + + (cond ((and bmkp-use-w32-browser-p (fboundp 'w32-browser) file) (w32-browser file)) + ((and (bookmark-prop-get bookmark 'file-handler) file) + (funcall (bookmark-prop-get bookmark 'file-handler) file)) + (old-info-node ; Emacs 20-21 Info bookmarks - no handler entry. + (progn (require 'info) + (Info-find-node file old-info-node) + (when pos (goto-char pos)))) + ((not (and bmkp-use-region pos end-pos (/= pos end-pos))) + ;; Single-position bookmark (no region). Go to it. + (bmkp-goto-position bmk file buf bufname pos + (bookmark-get-front-context-string bmk) + (bookmark-get-rear-context-string bmk))) + (t + ;; Bookmark with a region. Go to it and activate the region. + (if (and file (file-readable-p file) (not (buffer-live-p buf))) +;;; $$$$$$$ (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (with-current-buffer (find-file-noselect file) (setq buf (buffer-name))) + ;; No file found. If no buffer either, then signal that file doesn't exist. + (unless (or (and buf (get-buffer buf)) + (and bufname (get-buffer bufname) (not (string= buf bufname)))) + (signal 'bookmark-error-no-filename (list 'stringp file)))) + (set-buffer (or buf bufname)) + (when bmkp-jump-display-function + (save-current-buffer (funcall bmkp-jump-display-function (current-buffer))) + (raise-frame)) + (goto-char (if pos (min pos (point-max)) (point-max))) + (when (and pos (> pos (point-max))) (error "Bookmark position is beyond buffer end")) + ;; Activate region. Relocate it if it moved. Save relocated bookmark if confirm. + (funcall bmkp-handle-region-function bmk))) + ;; $$$$$$ The vanilla code returns nil, but there is no explanation of why and no code seems + ;; to use the return value. Perhaps we should return the bookmark instead? + nil)) ; Return nil if no file error. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg NO-REFRESH-P. +;; 2. Added bookmark default for interactive use. +;; 3. Added note about `S-delete' to doc string. +;; 4. Changed arg name: BOOKMARK -> BOOKMARK-NAME. +;; 5. Update Dired location too, for Dired bookmark. +;; 6. Refresh menu list, to show new location. +;; +;;;###autoload (autoload 'bookmark-relocate "bookmark+") +(defun bookmark-relocate (bookmark-name &optional no-refresh-p) ; Not bound + "Relocate the bookmark named BOOKMARK-NAME to another file. +You are prompted for the new file name. +Non-nil optional arg NO-REFRESH-P means do not refresh/rebuild the +bookmark-list display. + +Changes the file associated with the bookmark. +Useful when a file has been renamed after a bookmark was set in it. + +If you use Icicles, then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate." + (interactive (list (bookmark-completing-read "Bookmark to relocate" (bmkp-default-bookmark-name)))) + (bookmark-maybe-historicize-string bookmark-name) + (bookmark-maybe-load-default-file) + (let* ((icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (bookmark-filename (bookmark-get-filename bookmark-name)) + (new-filename (abbreviate-file-name + (expand-file-name + (read-file-name + (format "Relocate %s to: " bookmark-name) + (file-name-directory bookmark-filename)))))) + (bookmark-set-filename bookmark-name new-filename) + ;; Change location for Dired too, but not if different from original file name (e.g. a cons). + (let ((dired-dir (bookmark-prop-get bookmark-name 'dired-directory))) + (when (and dired-dir (equal dired-dir bookmark-filename)) + (bookmark-prop-set bookmark-name 'dired-directory new-filename)))) + (bmkp-maybe-save-bookmarks) + (when (and bookmark-bmenu-toggle-filenames (get-buffer bmkp-bmenu-buffer) + (get-buffer-window (get-buffer bmkp-bmenu-buffer) 0) + (not no-refresh-p)) + (with-current-buffer (get-buffer bmkp-bmenu-buffer) ; Do NOT just use `bmkp-refresh/rebuild-menu-list'. + (bmkp-refresh-menu-list bookmark-name)))) ; So display new location and `*' marker. + + +;; REPLACES ORIGINAL in `bookmark.el' (it was removed from `bookmark.el' in Emacs 24.3 - Emacs bug #19838). +;; +;; No change from original, except provide a better doc string. +;; +;;;###autoload (autoload 'bookmark-insert-current-bookmark "bookmark+") +(unless (fboundp 'bookmark-insert-current-bookmark) + (defun bookmark-insert-current-bookmark () ; Emacs 24.3+ + "Insert current-bookmark name or buffer file name, if none. +That is, if `bookmark-current-bookmark' in `bookmark-current-buffer' +is not nil then insert that." + (interactive) + (let ((str (with-current-buffer bookmark-current-buffer + (or bookmark-current-bookmark (bookmark-buffer-name))))) + (insert str)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added bookmark default for interactive use. +;; 2. Do not add any text properties here. That's done in `bmkp-bmenu-propertize-item'. +;; 3. Added note about `S-delete' to doc string. +;; 4. Changed arg name: BOOKMARK -> BOOKMARK-NAME. +;; +;;;###autoload (autoload 'bookmark-insert-location "bookmark+") +(defun bookmark-insert-location (bookmark-name &optional no-history) ; `C-x x I' (original: `C-x x f') + "Insert file or buffer name for the bookmark named BOOKMARK-NAME. +If a file is bookmarked, insert the recorded file name. +If a non-file buffer is bookmarked, insert the recorded buffer name. + +Optional arg NO-HISTORY means do not record BOOKMARK-NAME in +`bookmark-history'. + +If you use Icicles then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate." + (interactive + (let ((bmk (bookmark-completing-read "Insert bookmark location" (bmkp-default-bookmark-name)))) + (if (> emacs-major-version 21) (list bmk) bmk))) + (unless no-history (bookmark-maybe-historicize-string bookmark-name)) + (insert (bookmark-location bookmark-name))) ; Return the line inserted. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. The different `bookmark-get-bookmark' behavior from vanilla Emacs means we can get the right bookmark +;; if it has a name with property `bmkp-full-record', without looking it up in `bookmark-alist'. +;; But we don't require that BOOKMARK have a name, so calls from vanilla or other code aren't bothered. +;; 2. Pass full bookmark to the various "get" functions. +;; 3. Location returned can be a buffer name. +;; +(defun bookmark-location (bookmark) + "Return a description of the location of BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +If it is a name with text property `bmkp-full-record', or if it is a +bookmark record, then it is NOT looked up in `bookmark-alist' (it need +not belong). If it is a name without that property then it is looked +up in `bookmark-alist'. + +Look first for entry `location', then for entry `buffer-name' or +`buffer', then for entry `filename'. Return the first such entry +found, or \"-- Unknown location --\" if none is found." + (bookmark-maybe-load-default-file) + (setq bookmark (bookmark-get-bookmark bookmark)) + (or (bookmark-prop-get bookmark 'location) + (bmkp-get-buffer-name bookmark) ; Entry `buffer-name'. + (bookmark-prop-get bookmark 'buffer) ; Entry `buffer'. + (bookmark-get-filename bookmark) + "-- Unknown location --")) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added BATCHP arg. Return OLD if BATCHP is non-nil and NEW is nil. +;; 2. Use `bmkp-completing-read-lax', not `read-from-minibuffer', for new name. +;; 3. Put `bmkp-full-record' property on new name. +;; 4. Rename also in marked and omitted lists. +;; 5. Added note about `S-delete' to doc string. +;; 6. Refresh menu list, to show new name. +;; +;;;###autoload (autoload 'bookmark-rename "bookmark+") +(defun bookmark-rename (old &optional new batchp) ; Not bound in Bookmark+ + "Change bookmark's name from OLD to NEW. +Interactively: + If called from the keyboard, then prompt for OLD. + If called from the menubar, select OLD from a menu. +If NEW is nil, then prompt for its string value (unless BATCH). + +When entering the NEW name you can use completion against existing +bookmark names. This completion is lax, so you can easily edit an +existing name. See `bookmark-set' for particular keys available +during this input. + +If BATCHP is non-nil, then do not rebuild the bookmark list. (NEW +should be non-nil if BATCH is non-nil.) + +If you use Icicles then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate." + (interactive (list (bookmark-completing-read "Old bookmark name" (bmkp-default-bookmark-name)))) + (bookmark-maybe-historicize-string old) + (bookmark-maybe-load-default-file) + (setq bookmark-current-point (point)) ; `bookmark-current-point' is a free var here. + (save-excursion (skip-chars-forward " ") (setq bookmark-yank-point (point))) + (setq bookmark-current-buffer (current-buffer)) + (let ((newname (or new (and (not batchp) (bmkp-completing-read-lax "New name" old))))) +;;; $$$$$$ (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)))) + (when newname + (bookmark-set-name old newname) ; (This also puts `bmkp-full-record' on bookmark name.) + (bmkp-rename-for-marked-and-omitted-lists old newname) ; Rename in marked & omitted lists, if present. + (setq bookmark-current-bookmark newname) + (unless batchp + (if (and (get-buffer bmkp-bmenu-buffer) (get-buffer-window (get-buffer bmkp-bmenu-buffer) 0)) + (with-current-buffer (get-buffer bmkp-bmenu-buffer) + (bmkp-refresh-menu-list newname)) ; So the new name is displayed. + (bookmark-bmenu-surreptitiously-rebuild-list))) + (bmkp-maybe-save-bookmarks)) + (or newname old))) ; NEWNAME is nil only if BATCHP is non-nil and NEW was nil. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added bookmark default for interactive use. +;; 2. Added note about `S-delete' to doc string. +;; 3. Changed arg name: BOOKMARK -> BOOKMARK-NAME. +;; +(or (fboundp 'bmkp-ORIG-bookmark-insert) +(fset 'bmkp-ORIG-bookmark-insert (symbol-function 'bookmark-insert))) + +;;;###autoload (autoload 'bookmark-insert "bookmark+") +(defun bookmark-insert (bookmark-name) ; Bound to `C-x x i' + "Insert the text of a bookmarked file. +BOOKMARK-NAME is the name of the 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 function `bookmark-load' for more about this. + +If you use Icicles, then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate." + (interactive (list (bookmark-completing-read "Insert bookmark contents" (bmkp-default-bookmark-name)))) + (bmkp-ORIG-bookmark-insert bookmark-name)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Accept a bookmark or a bookmark name as arg. +;; 2. Use `bmkp-default-bookmark-name' as default when interactive. +;; 3. Use `bmkp-get-bookmark' instead of `bookmark-get-bookmark', so we can get the right bookmark if +;; it has a name with property `bmkp-full-record'. +;; 4. Use `bmkp-get-bookmark-in-alist', not `bookmark-get-bookmark', when checking `bookmark-current-bookmark'. +;; 5. Remove highlighting for the bookmark. +;; 6. Doc string includes note about `S-delete' for Icicles. +;; 7. Update `bmkp-latest-bookmark-alist', `bmkp-bmenu-omitted-bookmarks', and `bmkp-automatic-bookmarks'. +;; 8. Increment `bookmark-alist-modification-count' even when BATCHP is non-nil. +;; +;;;###autoload (autoload 'bookmark-delete "bookmark+") +(defun bookmark-delete (bookmark &optional batchp) ; Bound to `C-x x d' + "Delete the BOOKMARK from the bookmark list. +BOOKMARK is a bookmark name or a bookmark record. +Interactively, default to the \"current\" bookmark (that is, the one +most recently used in this file), if it exists. + +If BOOKMARK is a name and it has property `bmkp-full-record' then use +that property along with the name to find the bookmark to delete. If +it is or has a name without property `bmkp-full-record' then +delete (only) the first bookmark in `bookmark-alist' with that name. + +Optional arg BATCHP means do not update buffer `*Bookmark List*'. + +If you use Icicles, then you can use `S-delete' during completion of a +bookmark name to delete the bookmark named by the current completion +candidate. In this way, you can delete multiple bookmarks." + (interactive (list (bookmark-completing-read "Delete bookmark" (bmkp-default-bookmark-name)))) + + ;; $$$$$$ Instead of loading unconditionally, maybe we should just try to delete conditionally? + ;; IOW, why not (when bookmarks-already-loaded BODY) instead of `bookmark-maybe-load-default-file'? + ;; If it gets called on a hook that gets run before ever loading, then should probably do nothing. + ;; Leaving it as is for now (2011-04-06). + (bookmark-maybe-load-default-file) + (let* ((bmk (bmkp-get-bookmark bookmark 'NOERROR)) + (bname (bmkp-bookmark-name-from-record bmk))) ; BOOKMARK might have been a bookmark. + (when bname ; Do nothing if BOOKMARK does not represent a bookmark. + (bookmark-maybe-historicize-string bname) + (when (fboundp 'bmkp-unlight-bookmark) (bmkp-unlight-bookmark bmk 'NOERROR)) + (setq bookmark-alist (delq bmk bookmark-alist) + bmkp-latest-bookmark-alist (delq bmk bmkp-latest-bookmark-alist) + bmkp-automatic-bookmarks (delq bmk bmkp-automatic-bookmarks) + bmkp-bmenu-omitted-bookmarks (bmkp-delete-bookmark-name-from-list + bname bmkp-bmenu-omitted-bookmarks)) + (unless (bmkp-get-bookmark-in-alist bookmark-current-bookmark 'NOERROR) + (setq bookmark-current-bookmark nil)) ; Make this nil if last occurrence of BMK was deleted. + ;; Do NOT refresh/rebuild if BATCHP. Caller must do that if batching deletions. + (unless batchp (bmkp-refresh/rebuild-menu-list)) + (bmkp-maybe-save-bookmarks)))) ; Increments `bookmark-alist-modification-count'. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Use `bmkp-current-bookmark-file', not `bookmark-default-file'. +;; 2. Update `bmkp-last-as-first-bookmark-file' if it is non-nil. +;; 3. Reset `bmkp-modified-bookmarks' to (). +;; 4. Call `bmkp-refresh/rebuild-menu-list'. +;; +;;;###autoload (autoload 'bookmark-save "bookmark+") +(defun bookmark-save (&optional parg file) ; Bound to `C-x x s' + "Save currently defined bookmarks. +Save by default in the file named by variable +`bmkp-current-bookmark-file'. With a prefix arg, you are prompted for +the file to save to. + +If `bmkp-last-as-first-bookmark-file' is non-nil, update its value to +the file being saved. + +To load bookmarks from a specific file, use `\\[bookmark-load]' +\(`bookmark-load'). + +If called from Lisp: + With nil PARG and nil FILE, use file `bmkp-current-bookmark-file'. + With non-nil FILE, use file FILE. + With non-nil PARG, prompt the user for the file to use." + (interactive "P") + (bookmark-maybe-load-default-file) + (let ((file-to-save + (cond (file) ; Use FILE provided. + (parg (bmkp-read-bookmark-file-name + "File to save bookmarks in: " nil + (bmkp-read-bookmark-file-default))) + ((not parg) bmkp-current-bookmark-file)))) + (when (file-directory-p file-to-save) (error "`%s' is a directory, not a file" file-to-save)) + (when (and bmkp-last-as-first-bookmark-file + bookmark-save-flag) ; nil if temporary bookmarking mode. + (customize-save-variable 'bmkp-last-as-first-bookmark-file file-to-save)) + (bookmark-write-file file-to-save)) + ;; Indicate by the count that we have synced the current bookmark file. + ;; If an error has already occurred somewhere, the count will not be set, which is what we want. + (setq bookmark-alist-modification-count 0 + bmkp-modified-bookmarks ()) + (bmkp-refresh/rebuild-menu-list)) ; $$$$$$ Should this be done only when interactive? + + +;; From `mule-util.el' +;; +(eval-when-compile + (defmacro with-coding-priority (coding-systems &rest body) + "Execute BODY like `progn' with CODING-SYSTEMS at the front of priority list. +CODING-SYSTEMS is a list of coding systems. See `set-coding-system-priority'. +This affects the implicit sorting of lists of coding systems returned by +operations such as `find-coding-systems-region'." + (let ((current (make-symbol "current"))) + `(let ((,current (coding-system-priority-list))) + (apply #'set-coding-system-priority ,coding-systems) + (unwind-protect + (progn ,@body) + (apply #'set-coding-system-priority ,current)))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Use `write-file', not `write-region', so backup files are made. +;; 2. Do not save temporary bookmarks (`bmkp-temporary-bookmark-p'). +;; 3. Added optional arguments ADD and ALT-MSG. +;; Do not delete region if ADD. Position point depending on ADD. +;; 4. Delete contents only if file does not exist (just in case). Else `bookmark-maybe-upgrade-file-format'. +;; 5. Insert code piecewise, to improve performance when saving `bookmark-alist'. +;; (Do not let `pp' parse all of `bookmark-alist' at once.) +;; 6. Unless `bmkp-propertize-bookmark-names-flag', remove text properties from bookmark name and file name. +;; Remove them also from bookmark names in a sequence bookmark `sequence' entry. +;; 7. Bind `print-circle' and `print-gensym' around `pp', to record bNAME with `bmkp-full-record' prop, when +;; appropriate. +;; 8. Use `case', not `cond'. +;; 9. Run `bmkp-write-bookmark-file-hook' functions after writing the bookmark file. +;; +(defun bookmark-write-file (file &optional add alt-msg) + "Write `bookmark-alist' to FILE. +Bookmarks that have a non-nil `bmkp-temp' entry are not saved. +They are removed from the bookmark file, but not from the current +bookmark list. + +Non-nil optional arg ADD means do not replace the bookmarks in FILE. +If the value is `append' then append `bookmark-list' to them. Any +other non-nil value means prepend `bookmark-list' to them. Prepending +means that for some operations the copied bookmarks take precedence +over existing ones with the same name (since an alist is used). + +Non-nil ALT-MSG is a message format string to use in place of the +default, \"Saving bookmarks to file `%s'...\". The string must +contain a `%s' construct, so that it can be passed along with FILE to +`format'. At the end, \"done\" is appended to the message." + (let ((msg (or alt-msg "Saving bookmarks to file `%s'...")) + (coding-system-for-write (if (boundp 'bookmark-file-coding-system) ; Emacs 25.2+. + (or coding-system-for-write bookmark-file-coding-system 'utf-8-emacs) + coding-system-for-write)) + (print-length nil) + (print-level nil) + (rem-all-p (or (not (> emacs-major-version 20)) ; Cannot: (not (boundp 'print-circle)). + (not bmkp-propertize-bookmark-names-flag))) + (existing-buf (get-file-buffer file)) + (emacs-lisp-mode-hook nil) ; Avoid inserting automatic file header if existing empty file, so + (lisp-mode-hook nil) ; better chance `bookmark-maybe-upgrade-file-format' signals error. + bname fname last-fname start end) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (message msg (abbreviate-file-name file)) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) + (if (file-exists-p file) + (bookmark-maybe-upgrade-file-format) + (delete-region (point-min) (point-max)) ; In case a find-file hook inserted a header, etc. + (unless (boundp 'bookmark-file-coding-system) ; Emacs < 25.2. + (bookmark-insert-file-format-version-stamp)) + (insert "(\n)")) + (setq start (and (file-exists-p file) + (or (save-excursion (goto-char (point-min)) + (search-forward (concat bookmark-end-of-version-stamp-marker "(") + nil t)) + (error "Invalid bookmark-file"))) + end (and start + (or (save-excursion (goto-char start) (and (looking-at ")") start)) ; Bmk list = (). + (save-excursion (goto-char (point-max)) (re-search-backward "^)" nil t)) + (error "Invalid bookmark-file")))) + (if (not start) ; New file, no header yet. + (goto-char 2) + ;; Existing file - delete old bookmarks unless ADD. + (unless add (delete-region start end)) + (goto-char (if (eq add 'append) end start))) + (dolist (bmk bookmark-alist) + (unless (bmkp-temporary-bookmark-p bmk) + (setq bname (bookmark-name-from-full-record bmk) + fname (bookmark-get-filename bmk)) + (cond (rem-all-p ; Remove text properties from bookmark name and file name. + (set-text-properties 0 (length bname) () bname) + (when fname (set-text-properties 0 (length fname) () fname))) + (t ; Remove property `face' and any Icicles internal properties. + (remove-text-properties 0 (length bname) '(face nil + display nil + help-echo nil + rear-nonsticky nil + icicle-fancy-candidates nil + icicle-mode-line-help nil + icicle-special-candidate nil + icicle-user-plain-dot nil + icicle-whole-candidate nil + invisible nil) + bname) + (when (boundp 'icicle-candidate-properties-alist) ; Multi-completion indexes + text props. + (dolist (entry icicle-candidate-properties-alist) + (put-text-property 0 (length bname) (car (cadr entry)) nil bname))))) + (setcar bmk bname) + (when (setq last-fname (assq 'filename bmk)) (setcdr last-fname fname)) + (let ((print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag)) + (if (not (and rem-all-p (bmkp-sequence-bookmark-p bmk))) + (pp bmk (current-buffer)) + ;; Remove text properties from bookmark names in the `sequence' entry of sequence bookmark. + (insert "(\"" (let ((seqbname (copy-sequence (bookmark-name-from-full-record bmk)))) + (set-text-properties 0 (length seqbname) () seqbname) + seqbname) + "\"\n") + (dolist (prop (cdr bmk)) + (if (not (eq 'sequence (car prop))) + (insert " " (pp-to-string prop)) + (insert " (sequence " (mapconcat (lambda (bname) + (let ((name (copy-sequence bname))) + (set-text-properties 0 (length name) () name) + (concat "\"" name "\""))) + (cdr prop) " ") + ")\n"))) + (insert " )\n"))))) + (when (boundp 'bookmark-file-coding-system) ; Emacs 25.2+. See bug #25365 + ;; Make sure specified encoding can encode the bookmarks. If not, suggest utf-8-emacs as default. + (with-coding-priority '(utf-8-emacs) + (setq coding-system-for-write (select-safe-coding-system (point-min) (point-max) + (list t coding-system-for-write)))) + (when start (delete-region 1 (1- start))) ; Delete old header. + (goto-char 1) + (bookmark-insert-file-format-version-stamp coding-system-for-write)) + (let ((version-control (case bookmark-version-control + ((nil) nil) + (never 'never) + (nospecial version-control) + (t t))) + (require-final-newline t) + (errorp nil)) + (condition-case nil + (write-file file) + (file-error (setq errorp t) + ;; Do NOT raise error. (Need to be able to exit.) + (let ((msg (format "CANNOT WRITE FILE `%s'" file))) + (if (fboundp 'display-warning) + (display-warning 'bookmark-plus msg) + (message msg) + (sit-for 4))))) + (when (boundp 'bookmark-file-coding-system) ; Emacs 25.2+ + (setq bookmark-file-coding-system coding-system-for-write)) + (unless existing-buf (kill-buffer (current-buffer))) + (run-hook-with-args 'bmkp-write-bookmark-file-hook file) + (unless errorp (message (concat msg "done") file)))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg DUPLICATES-OK. +;; +;; 2. Unless DUPLICATES-OK is non-nil, if a bookmark in NEW-LIST is `equal' to a bookmark in `bookmark-alist' +;; then do not rename it and do not add it - just ignore it. +;; +;; 3. Return value includes how many bookmarks were added and renamed. +;; If RETURN-BMKS is non-nil then it also includes which bookmarks were added. +;; +(defun bookmark-import-new-list (new-list &optional duplicates-ok return-bmks) + "Add NEW-LIST of bookmarks to `bookmark-alist'. +Unless optional arg DUPLICATES-OK is non-nil, ignore bookmarks that +are `equal' to bookmarks in `bookmark-alist'. (This means that all of +their information is `equal', not just their names. This includes +their tags and annotations.) + +Rename new bookmarks that are not ignored, as needed, using suffix +\"\" (N=2,3...) when they conflict with existing bookmark names. + +Return a list (NB-RENAMED NB-ADDED BMKS-ADDED) of the number renamed, +the number added, and the full bookmarks that were added. If +RETURN-BMKS is nil then BMKS-ADDED is just nil (the bookmarks are not +returned)." + (let ((names (bookmark-all-names)) + (nb-added 0) + (nb-renamed 0) + (bmks-added ())) + (dolist (full-bmk new-list) + (when (or (and (not (member full-bmk bookmark-alist)) ; Check even if DUPLICATES-OK, to update ADDEDP. + (setq nb-added (1+ nb-added))) + duplicates-ok) + (when (bookmark-maybe-rename full-bmk names) (setq nb-renamed (1+ nb-renamed))) + (setq bookmark-alist (nconc bookmark-alist (list full-bmk))) + (push (bookmark-name-from-full-record full-bmk) names) + (when return-bmks (push full-bmk bmks-added)))) + (list nb-renamed nb-added bmks-added))) + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Return non-nil iff bookmark was renamed. +;; +(defun bookmark-maybe-rename (full-record names) + "Rename bookmark FULL-RECORD if its current name is already used. +This is a helper for `bookmark-import-new-list'. +Return non-nil if the bookmark was renamed, nil otherwise." + (let ((found-name (bookmark-name-from-full-record full-record))) + (when (member found-name names) + (let ((count 2) + (new-name found-name)) + (while (member new-name names) + (setq new-name (concat found-name (format "<%d>" count)) + count (1+ count))) + (bookmark-set-name full-record new-name) + (not (string= found-name new-name)))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Prefix arg means OVERWRITE. +;; 2. Return the list of bookmarks read from FILE. +;; 3. Use `bmkp-read-bookmark-file-name', not `read-file-name', and use different default. +;; 4. If OVERWRITE is non-nil: +;; * Update `bmkp-last-bookmark-file' to `bmkp-current-bookmark-file'. +;; * Update `bmkp-current-bookmark-file' to FILE. +;; * Reset bmenu stuff: `bmkp-bmenu-marked-bookmarks', `bmkp-modified-bookmarks', +;; `bmkp-flagged-bookmarks', `bmkp-bmenu-omitted-bookmarks', `bmkp-bmenu-filter-function'. +;; * If `bmkp-last-as-first-bookmark-file', then update it to FILE and save it to disk. +;; 5. If the bookmark-file buffer already existed, do not kill it after loading. +;; 6. Set `bookmarks-already-loaded' regardless of FILE (not just `bookmark-default-file'). +;; 7. Update `bmkp-sorted-alist' (it's a cache). +;; 8. Final msg says whether overwritten. +;; 9. Run `bmkp-read-bookmark-file-hook' after reading the bookmark file. +;; 10. Call `bmkp-bmenu-refresh-menu-list' at end, if interactive. +;; +;;;###autoload (autoload 'bookmark-load "bookmark+") +(defun bookmark-load (file &optional overwrite batchp) ; Bound to `C-x x l' + "Load bookmarks from FILE (which must be in the standard format). +Return the list of bookmarks read from FILE. +Without a prefix argument (argument OVERWRITE is nil), add the newly +loaded bookmarks to those already current. They are saved to the +current bookmark file when bookmarks are saved. + +If you do not use a prefix argument, then no existing bookmarks are +overwritten. If you load some bookmarks that have the same names as +bookmarks already defined in your Emacs session, numeric suffixes +\"<2>\", \"<3>\",... are appended as needed to the names of those new +bookmarks to distinguish them. + +With a prefix argument, switch the bookmark file currently used, +*replacing* all currently existing bookmarks with the newly loaded +bookmarks. In this case, the value of `bmkp-current-bookmark-file'is +backed up to `bmkp-last-bookmark-file' and then changed to FILE, so +bookmarks will subsequently be saved to FILE. + +If `bmkp-last-as-first-bookmark-file' is non-nil and is not FILE then +it is changed to FILE and saved persistently, so that the next Emacs +session will start with it as the bookmark file. (The value of +`bookmark-default-file' is unaffected.) + +Interactively, if any bookmarks have been modified since last saved +then you are asked whether you want to first save them before loading +FILE. If you hit `C-g' then both saving and loading are canceled. + +`bookmark-load' runs `bmkp-read-bookmark-file-hook' after reading the +bookmark file. + +When called from Lisp, non-nil optional arg BATCHP means this is not +an interactive call. In this case, do not interact with the user: do +not ask whether to save the current (unsaved) bookmark list before +loading; do not display any load progress messages; and do not +update/refresh buffer `*Bookmark List*'. + +If BATCHP is `save' and bookmarks have been modified since the +bookmark list was last saved, then save the bookmark list before +loading. + +If BATCHP is any other non-nil value besides `save', do not save the +bookmark list. + +Your initial bookmark file, either `bmkp-last-as-first-bookmark-file' +or `bookmark-default-file', is loaded automatically by Emacs the first +time you use bookmarks in a session - you do not need to load it +manually. Use `bookmark-load' only to load extra bookmarks (with no +prefix arg) or an alternative set of bookmarks (with a prefix arg). + +If you use `bookmark-load' to load a file that does not contain a +proper bookmark alist, then when bookmarks are saved the current +bookmark file will likely become corrupted. You should load only +bookmark files that were created using the bookmark functions." + (interactive + (list (let ((default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (bmkp-default-bookmark-file) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name + (if current-prefix-arg "Switch to bookmark file: " "Add bookmarks from file: ") + (or (file-name-directory default) "~/") + default + t)) + current-prefix-arg)) + ;; Maybe save first. + (when (or (eq batchp 'save) + (and (not batchp) (> bookmark-alist-modification-count 0) + (condition-case err + (yes-or-no-p "Save current bookmarks before loading? (`C-g': cancel load) ") + (quit (error "OK, canceled")) + (error (error (error-message-string err)))))) + (bookmark-save)) + ;; Load. + (setq file (abbreviate-file-name (expand-file-name file))) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (unless (file-readable-p file) (error "Cannot read bookmark file `%s'" file)) + (unless batchp (message "Loading bookmarks from `%s'..." file)) + (let ((existing-buf (get-file-buffer file)) + blist) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) + (bookmark-maybe-upgrade-file-format) + (setq blist (bookmark-alist-from-buffer)) + (unless (listp blist) (error "Invalid bookmark list in `%s'" file)) + (cond (overwrite + (setq bmkp-last-bookmark-file bmkp-current-bookmark-file + bmkp-current-bookmark-file file + bookmark-alist blist + bookmark-alist-modification-count 0) + (setq bmkp-bmenu-marked-bookmarks () ; Start from scratch. + bmkp-modified-bookmarks () + bmkp-flagged-bookmarks () + bmkp-bmenu-omitted-bookmarks (condition-case nil + (eval (car (get 'bmkp-bmenu-omitted-bookmarks + 'saved-value))) + (error nil)) + bmkp-bmenu-filter-function nil) + (when (and bmkp-last-as-first-bookmark-file + (not (bmkp-same-file-p bmkp-last-as-first-bookmark-file file))) + (customize-save-variable 'bmkp-last-as-first-bookmark-file file))) + (t + (bookmark-import-new-list blist) + (setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count)))) + (setq bookmarks-already-loaded t ; Systematically, whenever any file is loaded. + bmkp-sorted-alist (bmkp-sort-omit bookmark-alist)) + (when (boundp 'bookmark-file-coding-system) ; Emacs 25.2+ + (setq bookmark-file-coding-system buffer-file-coding-system)) + (run-hook-with-args 'bmkp-read-bookmark-file-hook blist file) + (unless (eq existing-buf (current-buffer)) (kill-buffer (current-buffer)))) + (unless batchp ; If appropriate, *CALLER* MUST refresh/rebuild, if BATCHP. + (bmkp-refresh/rebuild-menu-list) + (message "%s bookmarks in `%s'" (if overwrite "Switched to" "Added") file)) + blist)) ; Return the list of bookmarks read from FILE. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Make it a command (added `interactive' spec). +;; 2. Use `bmkp-get-bookmark' instead of `bookmark-get-bookmark', so we can get the right bookmark if +;; it has a name with property `bmkp-full-record'. +;; 3. Handle external annotations (jump to their destinations). +;; 4. Added optional arg MSG-P. Show message if no annotation. +;; 5. If `bookmark-automatically-show-annotations' is `edit' then this is `bookmark-edit-annotation'. +;; 6. Name buffer after the bookmark. +;; 7. Highlight the title, using face `bmkp-heading'. +;; 8. MSG-P means message if no annotation. +;; 9. Set `bookmark-annotation-name'. +;; 10. Manage `buffer-modified-p'. +;; 11. Use `, not ', in title. (Both are tolerated.) +;; 12. Fit frame to buffer if `one-windowp'. +;; 13. Restore frame selection. +;; +;;;###autoload (autoload 'bookmark-show-annotation "bookmark+") +(defun bookmark-show-annotation (bookmark &optional msg-p) ; Bound to `C-x x a s' + "Show the annotation for BOOKMARK, or follow it if external. +BOOKMARK is a bookmark name or a bookmark record. +If it is a bookmark name then it is looked up in `bookmark-alist'. +If it is a record then it is NOT looked up (need not belong). +If it is or has a name that has non-nil property `bmkp-full-record', +then use the bookmark in `bookmark-alist' that is the value of that +property. Raise no error if it has no name. + +If the annotation is external then jump to its destination. +If no annotation and MSG-P is non-nil, show a no-annotation message. + +Opens in read-only or edit mode, as chosen by option +`bookmark-automatically-show-annotations'. You can toggle between +read-only and edit mode using `C-x C-q'." + (interactive (list (bookmark-completing-read "Show annotation of bookmark" + (bmkp-default-bookmark-name) + (bmkp-annotated-alist-only) + nil + nil + 'USE-NIL-ALIST-P))) + (let* ((bmk (bmkp-get-bookmark bookmark 'NOERROR)) + (bname (bmkp-bookmark-name-from-record bmk)) + (ann (and bmk (bookmark-get-annotation bmk))) + (external (and ann (bmkp-get-external-annotation ann)))) + (if external + (bmkp-visit-external-annotation external msg-p) + (if (not (and ann (not (string-equal ann "")))) + (when msg-p (message "Bookmark has no annotation")) + (if (eq 'edit bookmark-automatically-show-annotations) + (bookmark-edit-annotation bookmark) + (let ((oframe (selected-frame))) + (save-selected-window + (pop-to-buffer (get-buffer-create (format "*`%s' Annotation*" bname))) + (let ((buffer-read-only nil) ; Because buffer might already exist, in view mode. + (buf-modified-p (buffer-modified-p))) + (delete-region (point-min) (point-max)) + (insert (concat "Annotation for bookmark `" bname "':\n\n")) + ;; Use `font-lock-ignore' property from library `font-lock+.el', because Org mode + ;; uses font-lock, which would otherwise wipe out the highlighting added here. + (add-text-properties (line-beginning-position -1) (line-end-position 1) + '(face bmkp-heading + font-lock-ignore t)) + (insert ann) + (set-buffer-modified-p buf-modified-p)) + (goto-char (point-min)) + (bookmark-show-annotation-mode) + (when (fboundp 'fit-frame-if-one-window) (fit-frame-if-one-window)) + (setq bookmark-annotation-name bmk)) + (select-frame-set-input-focus oframe))))))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Make it a command (added `interactive' spec). +;; 2. Use `bookmark-maybe-load-default-file', to ensure bookmarks are loaded. +;; 3. Use name `*Bookmark Annotations*', not `*Bookmark Annotation*'. +;; 4. Don't list bookmarks that have no annotation. +;; 5. Highlight bookmark names. Don't indent annotations. Add a blank line after each annotation. +;; 6. Use `view-mode'. `q' uses `quit-window'. +;; 7. Fit frame to buffer if `one-windowp'. +;; 8. Restore frame selection. +;; +;;;###autoload (autoload 'bookmark-show-all-annotations "bookmark+") +(defun bookmark-show-all-annotations () ; Bound to `C-x x a S' + "Display the annotations for all bookmarks. +If called from buffer `*Bookmark List*' then the annotations are shown +in the current sort order." + (interactive) + (bookmark-maybe-load-default-file) + (let ((obuf (current-buffer)) + (oframe (selected-frame))) + (save-selected-window + (pop-to-buffer (get-buffer-create "*Bookmark Annotations*")) + (let ((buffer-read-only nil)) ; Because buffer might already exist, in view mode. + (delete-region (point-min) (point-max)) + ;; (Could use `bmkp-annotated-alist-only' here instead.) + (dolist (full-record (if (equal (buffer-name obuf) bmkp-bmenu-buffer) + (bmkp-sort-omit bookmark-alist + (and (not (eq bmkp-bmenu-filter-function + 'bmkp-omitted-alist-only)) + bmkp-bmenu-omitted-bookmarks)) + bookmark-alist)) + (let ((ann (bookmark-get-annotation full-record))) + (when (and ann (not (string-equal ann ""))) + (insert (concat (bmkp-bookmark-name-from-record full-record) ":\n")) + (put-text-property (line-beginning-position 0) (line-end-position 0) 'face 'bmkp-heading) + (insert ann) (unless (bolp) (insert "\n\n"))))) + (goto-char (point-min)) + (if (> emacs-major-version 23) ; Incompatible change introduced in Emacs 24.1 + (view-mode-enter) + (view-mode-enter (cons (selected-window) (cons nil 'quit-window)))) + (when (fboundp 'fit-frame-if-one-window) (fit-frame-if-one-window)))) + (select-frame-set-input-focus oframe))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Save menu-list state to `bmkp-bmenu-state-file'. +;; +(defun bookmark-exit-hook-internal () ; This goes on `kill-emacs-hook'. + "Save currently defined bookmarks and perhaps bookmark menu-list state. +Run `bookmark-exit-hook', then save bookmarks if they were updated. +Then save menu-list state to file `bmkp-bmenu-state-file', but only if +that option is non-nil." + (run-hooks 'bookmark-exit-hook) + (when (bookmark-time-to-save-p t) + (condition-case err ; Do NOT raise error. (Need to be able to exit.) + (bookmark-save) + (error (if (fboundp 'display-warning) + (display-warning 'bookmark-plus (error-message-string err)) + (message (error-message-string err)) + (sit-for 4)) + nil))) + (bmkp-save-menu-list-state)) + +;;(@* "Bookmark+ Functions (`bmkp-*')") +;;; Bookmark+ Functions (`bmkp-*') ----------------------------------- + + +;;(@* "Filter Functions") +;; *** Filter Functions *** + +(put 'bmkp-all-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-all-tags-alist-only (tags) + "`bookmark-alist', but with only bookmarks having all their tags in TAGS. +Does not include bookmarks that have no tags. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lambda (bmk) + (lexical-let* ((tgs tags) + (bmk-tags (bmkp-get-tags bmk))) + (and bmk-tags (bmkp-every (lambda (tag) (member (bmkp-tag-name tag) tgs)) bmk-tags)))) + bookmark-alist)) + +(put 'bmkp-all-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-all-tags-regexp-alist-only (regexp) + "`bookmark-alist', but with only bookmarks having all tags match REGEXP. +Does not include bookmarks that have no tags. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) + (let ((bmk-tags (bmkp-get-tags bmk))) + (and bmk-tags + (bmkp-every (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) bmk-tags))))) + bookmark-alist)) + +(defun bmkp-annotated-alist-only () + "`bookmark-alist', but only for bookmarks with non-empty annotations. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-annotated-bookmark-p bookmark-alist)) + +(defun bmkp-autofile-alist-only (&optional prefix) + "`bookmark-alist', filtered to retain only autofile bookmarks. +With non-nil arg PREFIX, the bookmark names must all have that PREFIX." + (bookmark-maybe-load-default-file) + (if (not prefix) + (bmkp-remove-if-not #'bmkp-autofile-bookmark-p bookmark-alist) + (bmkp-remove-if-not (lexical-let ((pref prefix)) (lambda (bmk) (bmkp-autofile-bookmark-p bmk pref))) + bookmark-alist))) + +(put 'bmkp-autofile-all-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-autofile-all-tags-alist-only (tags) + "`bookmark-alist', with only autofiles having all tags in TAGS. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((tgs tags)) + (lambda (bmk) + (and (bmkp-autofile-bookmark-p bmk) (bmkp-get-tags bmk) + (bmkp-every (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) tgs)))) + bookmark-alist)) + +(put 'bmkp-autofile-all-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-autofile-all-tags-regexp-alist-only (regexp) + "`bookmark-alist', with only autofiles having all tags match REGEXP. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) + (and (bmkp-autofile-bookmark-p bmk) + (let ((bmk-tags (bmkp-get-tags bmk))) + (and bmk-tags + (bmkp-every (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) bmk-tags)))))) + bookmark-alist)) + +(put 'bmkp-autofile-some-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-autofile-some-tags-alist-only (tags) + "`bookmark-alist', with only autofiles having some tags in TAGS. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lambda (bmk) (and (bmkp-autofile-bookmark-p bmk) + (bmkp-some (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) tags))) + bookmark-alist)) + +(put 'bmkp-autofile-some-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-autofile-some-tags-regexp-alist-only (regexp) + "`bookmark-alist', with only autofiles having some tags match REGEXP. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) (and (bmkp-autofile-bookmark-p bmk) + (bmkp-some (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + (bmkp-get-tags bmk))))) + bookmark-alist)) +(defun bmkp-autonamed-alist-only () + "`bookmark-alist', with only autonamed bookmarks (from any buffers). +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-autonamed-bookmark-p bookmark-alist)) + +(defun bmkp-autonamed-this-buffer-alist-only () + "`bookmark-alist', with only autonamed bookmarks for the current buffer. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) (bmkp-autonamed-this-buffer-bookmark-p bmk)) bookmark-alist)) + +(defun bmkp-bookmark-file-alist-only () + "`bookmark-alist', filtered to retain only bookmark-file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-bookmark-file-bookmark-p bookmark-alist)) + +(defun bmkp-bookmark-list-alist-only () + "`bookmark-alist', filtered to retain only bookmark-list bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-bookmark-list-bookmark-p bookmark-alist)) + +(defun bmkp-buffer-alist-only () + "`bookmark-alist', filtered to retain only non-file buffer bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-buffer-bookmark-p bookmark-alist)) + +(defun bmkp-desktop-alist-only () + "`bookmark-alist', filtered to retain only desktop bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-desktop-bookmark-p bookmark-alist)) + +(defun bmkp-dired-alist-only () + "`bookmark-alist', filtered to retain only Dired bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-dired-bookmark-p bookmark-alist)) + +(defun bmkp-dired-this-dir-alist-only () + "`bookmark-alist', with only Dired bookmarks for the current directory. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-dired-this-dir-bookmark-p bookmark-alist)) + +(defun bmkp-dired-wildcards-alist-only () + "`bookmark-alist', with only bookmarks for a Dired buffer with wildcards. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-dired-wildcards-bookmark-p bookmark-alist)) + +(when (fboundp 'bmkp-eww-bookmark-p) ; Emacs 25+ + + (defun bmkp-eww-alist-only () + "`bookmark-alist', filtered to retain only EWW bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-eww-bookmark-p bookmark-alist)) + + ) + +(defun bmkp-file-alist-only () + "`bookmark-alist', filtered to retain only file and directory bookmarks. +This excludes bookmarks that might contain file information but are +particular in some way - for example, Info bookmarks or Gnus bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-file-bookmark-p bookmark-alist)) + +(put 'bmkp-file-all-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-file-all-tags-alist-only (tags) + "`bookmark-alist', with only file bookmarks having all tags in TAGS. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((tgs tags)) + (lambda (bmk) + (and (bmkp-file-bookmark-p bmk) (bmkp-get-tags bmk) + (bmkp-every (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) tgs)))) + bookmark-alist)) + +(put 'bmkp-file-all-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-file-all-tags-regexp-alist-only (regexp) + "`bookmark-alist', with only file bookmarks having all tags match REGEXP. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) + (and (bmkp-file-bookmark-p bmk) + (let ((bmk-tags (bmkp-get-tags bmk))) + (and bmk-tags + (bmkp-every (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) bmk-tags)))))) + bookmark-alist)) + +(put 'bmkp-file-some-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-file-some-tags-alist-only (tags) + "`bookmark-alist', with only file bookmarks having some tags in TAGS. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((tgs tags)) + (lambda (bmk) (and (bmkp-file-bookmark-p bmk) + (bmkp-some (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) tgs)))) + bookmark-alist)) + +(put 'bmkp-file-some-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-file-some-tags-regexp-alist-only (regexp) + "`bookmark-alist', with only file bookmarks having some tags match REGEXP. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) (and (bmkp-file-bookmark-p bmk) + (bmkp-some (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + (bmkp-get-tags bmk))))) + bookmark-alist)) + +(defun bmkp-file-this-dir-alist-only () + "`bookmark-alist', filtered with `bmkp-file-this-dir-bookmark-p'. +Include only files and subdir that are in `default-directory'. +This excludes bookmarks that might contain file information but are +particular in some way - for example, Info bookmarks or Gnus bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-file-this-dir-bookmark-p bookmark-alist)) + +(put 'bmkp-file-this-dir-all-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-file-this-dir-all-tags-alist-only (tags) + "`bookmark-alist', for files in this dir having all tags in TAGS. +Include only files and subdir that are in `default-directory'. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((tgs tags)) + (lambda (bmk) + (and (bmkp-file-this-dir-bookmark-p bmk) (bmkp-get-tags bmk) + (bmkp-every (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) tgs)))) + bookmark-alist)) + +(put 'bmkp-file-this-dir-all-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-file-this-dir-all-tags-regexp-alist-only (regexp) + "`bookmark-alist', for files in this dir having all tags match REGEXP. +Include only files and subdir that are in `default-directory'. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) + (and (bmkp-file-this-dir-bookmark-p bmk) + (let ((bmk-tags (bmkp-get-tags bmk))) + (and bmk-tags + (bmkp-every (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) bmk-tags)))))) + bookmark-alist)) + +(put 'bmkp-file-this-dir-some-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-file-this-dir-some-tags-alist-only (tags) + "`bookmark-alist', for files in this dir having some tags in TAGS. +Include only files and subdir that are in `default-directory'. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((tgs tags)) + (lambda (bmk) (and (bmkp-file-this-dir-bookmark-p bmk) + (bmkp-some (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) tgs)))) + bookmark-alist)) + +(put 'bmkp-file-this-dir-some-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-file-this-dir-some-tags-regexp-alist-only (regexp) + "`bookmark-alist', for files in this dir having some tags match REGEXP. +Include only files and subdir that are in `default-directory'. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lexical-let ((rg regexp)) + (lambda (bmk) (and (bmkp-file-this-dir-bookmark-p bmk) + (bmkp-some (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + (bmkp-get-tags bmk))))) + bookmark-alist)) + +(defun bmkp-function-alist-only () + "`bookmark-alist', filtered to retain only function bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-function-bookmark-p bookmark-alist)) + +(defun bmkp-gnus-alist-only () + "`bookmark-alist', filtered to retain only Gnus bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-gnus-bookmark-p bookmark-alist)) + +(defun bmkp-icicles-search-hits-alist-only () + "`bookmark-alist', but only for Icicles search hits bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-icicles-search-hits-bookmark-p bookmark-alist)) + +(defun bmkp-image-alist-only () + "`bookmark-alist', filtered to retain only image-file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-image-bookmark-p bookmark-alist)) + +(defun bmkp-info-alist-only () + "`bookmark-alist', filtered to retain only Info bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-info-bookmark-p bookmark-alist)) + +(defun bmkp-last-specific-buffer-alist-only () + "`bookmark-alist', but only for `bmkp-last-specific-buffer'. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-last-specific-buffer-p bookmark-alist)) + +(defun bmkp-last-specific-file-alist-only () + "`bookmark-alist', but only for `bmkp-last-specific-file'. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-last-specific-file-p bookmark-alist)) + +(defun bmkp-man-alist-only () + "`bookmark-alist', filtered to retain only `man' page bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-man-bookmark-p bookmark-alist)) + +(defun bmkp-local-file-alist-only () + "`bookmark-alist', filtered to retain only local-file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-local-file-bookmark-p bookmark-alist)) + +(defun bmkp-local-non-dir-file-alist-only () + "`bookmark-alist', filtered to retain only local non-dir file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-local-non-dir-file-bookmark-p bookmark-alist)) + +(defun bmkp-marked-bookmarks-only () + "Return the list of marked bookmarks." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-marked-bookmark-p bookmark-alist)) + +(defun bmkp-non-autonamed-alist-only () + "`bookmark-alist', with only non-autonamed bookmarks (from any buffers). +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) (not (bmkp-autonamed-bookmark-p bmk))) bookmark-alist)) + +(defun bmkp-non-dir-file-alist-only () + "`bookmark-alist', filtered to retain only nondirectory file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-non-dir-file-bookmark-p bookmark-alist)) + +(defun bmkp-non-file-alist-only () + "`bookmark-alist', filtered to retain only non-file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-non-file-bookmark-p bookmark-alist)) + +(defun bmkp-non-invokable-alist-only () + "`bookmark-alist', filtered to retain only non-invokable bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-non-invokable-bookmark-p bookmark-alist)) + +(defun bmkp-omitted-alist-only () + "`bookmark-alist', filtered to retain only the omitted bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-omitted-bookmark-p bookmark-alist)) + +(defun bmkp-omitted-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an omitted bookmark. +BOOKMARK is a bookmark name or a bookmark record." + (unless (stringp bookmark) (setq bookmark (bmkp-bookmark-name-from-record bookmark))) + (bmkp-bookmark-name-member bookmark bmkp-bmenu-omitted-bookmarks)) + +(defun bmkp-orphaned-file-alist-only () + "`bookmark-alist', filtered to retain only orphaned file bookmarks." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-orphaned-file-bookmark-p bookmark-alist)) + +(defun bmkp-orphaned-local-file-alist-only () + "`bookmark-alist', but retaining only orphaned local-file bookmarks." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-orphaned-local-file-bookmark-p bookmark-alist)) + +(defun bmkp-orphaned-remote-file-alist-only () + "`bookmark-alist', but retaining only orphaned remote-file bookmarks." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-orphaned-remote-file-bookmark-p bookmark-alist)) + +(defun bmkp-regexp-filtered-annotation-alist-only () + "`bookmark-alist' for annotations matching `bmkp-bmenu-filter-pattern'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not + (lambda (bmk) + (let ((annot (bookmark-get-annotation bmk))) + (and (stringp annot) (not (string= "" annot)) + (bmkp-string-match-p bmkp-bmenu-filter-pattern annot)))) + bookmark-alist)) ; (Could use `bmkp-annotated-alist-only' here instead.) + +(defun bmkp-regexp-filtered-bookmark-name-alist-only () + "`bookmark-alist' for bookmarks matching `bmkp-bmenu-filter-pattern'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) + (bmkp-string-match-p bmkp-bmenu-filter-pattern (bookmark-name-from-full-record bmk))) + bookmark-alist)) + +(defun bmkp-regexp-filtered-file-name-alist-only () + "`bookmark-alist' for files matching `bmkp-bmenu-filter-pattern'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) (let ((fname (bookmark-get-filename bmk))) + (and fname (bmkp-string-match-p bmkp-bmenu-filter-pattern fname)))) + bookmark-alist)) + +(defun bmkp-regexp-filtered-tags-alist-only () + "`bookmark-alist' for tags matching `bmkp-bmenu-filter-pattern'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) + (let ((bmk-tags (bmkp-get-tags bmk))) + (and bmk-tags (bmkp-some (lambda (tag) + (bmkp-string-match-p bmkp-bmenu-filter-pattern + (bmkp-tag-name tag))) + bmk-tags)))) + bookmark-alist)) + +(defun bmkp-region-alist-only () + "`bookmark-alist', filtered to retain only bookmarks that have regions. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-region-bookmark-p bookmark-alist)) + +(defun bmkp-remote-file-alist-only () + "`bookmark-alist', filtered to retain only remote-file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-remote-file-bookmark-p bookmark-alist)) + +(defun bmkp-remote-non-dir-file-alist-only () + "`bookmark-alist', filtered to retain only remote non-dir file bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-remote-non-dir-file-bookmark-p bookmark-alist)) + +(defun bmkp-sequence-alist-only () + "`bookmark-alist', filtered to retain only sequence bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-sequence-bookmark-p bookmark-alist)) + +(defun bmkp-snippet-alist-only () + "`bookmark-alist', filtered to retain only snippet bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-snippet-bookmark-p bookmark-alist)) + +(put 'bmkp-some-tags-alist-only 'bmkp-read-arg 'bmkp-read-tags-completing) +(defun bmkp-some-tags-alist-only (tags) + "`bookmark-alist', but with only bookmarks having some tags in TAGS. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lexical-let ((tgs tags)) + (lambda (bmk) + (bmkp-some (lexical-let ((bk bmk)) (lambda (tag) (bmkp-has-tag-p bk tag))) + tgs))) + bookmark-alist)) + +(put 'bmkp-some-tags-regexp-alist-only 'bmkp-read-arg 'bmkp-read-regexp) +(defun bmkp-some-tags-regexp-alist-only (regexp) + "`bookmark-alist', but with only bookmarks having some tags match REGEXP. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lexical-let ((rg regexp)) + (lambda (bmk) + (bmkp-some (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + (bmkp-get-tags bmk)))) + bookmark-alist)) + +(put 'bmkp-specific-buffers-alist-only 'bmkp-read-arg 'bmkp-read-buffers) +(defun bmkp-specific-buffers-alist-only (&optional buffers) + "`bookmark-alist', filtered to retain only bookmarks to buffers BUFFERS. +BUFFERS is a list of buffer names. +It defaults to a singleton list with the current buffer's name. +A new list is returned (no side effects). + +Note: Bookmarks created by vanilla Emacs do not record the buffer +name. They are therefore excluded from the returned alist." + (unless buffers (setq buffers (list (buffer-name)))) + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lexical-let ((bufs buffers)) + (lambda (bmk) + (and (not (bmkp-desktop-bookmark-p bmk)) ; Exclude these + (not (bmkp-bookmark-file-bookmark-p bmk)) + (not (bmkp-sequence-bookmark-p bmk)) + (not (bmkp-function-bookmark-p bmk)) + (not (bmkp-variable-list-bookmark-p bmk)) + (member (bmkp-get-buffer-name bmk) bufs)))) + bookmark-alist)) + +(put 'bmkp-specific-files-alist-only 'bmkp-read-arg 'bmkp-read-files) +(defun bmkp-specific-files-alist-only (&optional files) + "`bookmark-alist', filtered to retain only bookmarks to files FILES. +FILES is a list of absolute file names. +It defaults to a singleton list with the current buffer's file name, + or to the empty list if the buffer is not visiting a file. +A new list is returned (no side effects)." + (unless files (setq files (and (buffer-file-name) (list (buffer-file-name))))) + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lexical-let ((ff files)) + (lambda (bmk) + (let ((bf (bookmark-get-filename bmk))) + (and bf + ;; If we loaded `cl-seq.el': (cl-member bf ff :test #'bmkp-same-file-p) + (catch 'bmkp-specific-files-alist-only + (dolist (f ff) + (or (bmkp-same-file-p f bf) (throw 'bmkp-specific-files-alist-only nil))) + t))))) + bookmark-alist)) + +(defun bmkp-tagged-alist-only () + "`bookmark-alist', with only bookmarks that have tags. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-get-tags bookmark-alist)) + +(defun bmkp-temporary-alist-only () + "`bookmark-alist', filtered to retain only temporary bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-temporary-bookmark-p bookmark-alist)) + +(defun bmkp-this-file/buffer-alist-only () + "`bookmark-alist', with only bookmarks for the current file/buffer. +A new list is returned (no side effects). +If visiting a file, this is `bmkp-this-file-alist-only'. +Otherwise, this is `bmkp-this-buffer-alist-only'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (if (buffer-file-name) #'bmkp-this-file-p #'bmkp-this-buffer-p) bookmark-alist)) + +(defun bmkp-this-buffer-alist-only () + "`bookmark-alist', with only bookmarks for the current buffer. +A new list is returned (no side effects). +See `bmkp-this-buffer-p'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-this-buffer-p bookmark-alist)) + +(defun bmkp-this-file-alist-only () + "`bookmark-alist', with only bookmarks for the current file. +A new list is returned (no side effects). +See `bmkp-this-file-p'." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-this-file-p bookmark-alist)) + +(defun bmkp-unmarked-bookmarks-only () + "Return the list of unmarked bookmarks." + (bookmark-maybe-load-default-file) + (bmkp-remove-if #'bmkp-marked-bookmark-p bookmark-alist)) + +(defun bmkp-untagged-alist-only () + "`bookmark-alist', with only bookmarks that do not have tags. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if #'bmkp-get-tags bookmark-alist)) + +(defun bmkp-url-alist-only () + "`bookmark-alist', filtered to retain only URL bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-url-bookmark-p bookmark-alist)) + +(defun bmkp-url-browse-alist-only () + "`bookmark-alist', but with only URL bookmarks that are non-W3M, non-EWW. +\(The bookmarks satisfy `bmkp-url-browse-bookmark-p'.) +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-url-browse-bookmark-p bookmark-alist)) + +(defun bmkp-variable-list-alist-only () + "`bookmark-alist', filtered to retain only variable-list bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-variable-list-bookmark-p bookmark-alist)) + +(defun bmkp-w3m-alist-only () + "`bookmark-alist', filtered to retain only W3M bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not #'bmkp-w3m-bookmark-p bookmark-alist)) + +;; This provides the `defvar's for all Bookmark+ history variables. +;; Use this again, after you define any of your own filter functions +;; `bmkp-*-alist-only', for new kinds of bookmarks. +;; +(bmkp-define-history-variables) ; Macro defined in `bookmark+-mac.el'. + + +;;(@* "Miscellaneous Bookmark+ Functions") +;; *** Miscellaneous Bookmark+ Functions *** + +(if (fboundp 'find-tag-default-as-regexp) + (defun bmkp-read-regexp (&optional prompt defaults history) + "Same as `read-regexp', except argument PROMPT is optional. +PROMPT defaults to \"Regexp: \"." + (unless prompt (setq prompt "Regexp: ")) + (read-regexp prompt defaults history)) + + ;; Same as `icicle-find-tag-default-as-regexp' in `icicles-fn.el'. + (defun bmkp-find-tag-default-as-regexp () ; Emacs < 24.3 + "Return a regexp that matches the default tag at point. +If there is no tag at point, return nil. + +When in a major mode that does not provide its own +`find-tag-default-function', return a regexp that matches the +symbol at point exactly." + (let* ((tagf (or find-tag-default-function + (get major-mode 'find-tag-default-function) + 'find-tag-default)) + (tag (funcall tagf))) + (and tag (if (eq tagf 'find-tag-default) + (format "\\_<%s\\_>" (regexp-quote tag)) + (regexp-quote tag))))) + + ;; Same as `icicle-read-regexp' in `icicles-fn.el'. + (if (fboundp 'find-tag-default) + (defun bmkp-read-regexp (&optional prompt default history) ; Emacs 22-24.2 + "Read and return a regular expression as a string. +If PROMPT does not end with a colon and possibly whitespace then +append \": \" to it. + +PROMPT defaults to \"Regexp: \". + +Optional argument DEFAULT is a string or a list of the form +\(DEFLT . SUGGESTIONS), where DEFLT is a string or nil. + +The string DEFAULT or DEFLT is added to the prompt and is returned as +the default value if the user enters empty input. The empty string is +returned if DEFAULT or DEFLT is nil and the user enters empty input. + +SUGGESTIONS is used only for Emacs 23 and later. It is a list of +strings that can be inserted into the minibuffer using `\\\\[next-history-element]'. +The values supplied in SUGGESTIONS are prepended to the list of +standard suggestions, which include the tag at point, the last isearch +regexp, the last isearch string, and the last replacement regexp. + +Optional argument HISTORY is a symbol to use for the history list. +If nil then use `regexp-history'." + (unless prompt (setq prompt "Regexp: ")) + (let* ((deflt (if (consp default) (car default) default)) + (suggestions (and (> emacs-major-version 22) + (if (listp default) default (list default)))) + (suggestions (and (> emacs-major-version 22) + (append + suggestions + (list (bmkp-find-tag-default-as-regexp) + (car regexp-search-ring) + (regexp-quote (or (car search-ring) "")) + (car (symbol-value query-replace-from-history-variable)))))) + (suggestions (and (> emacs-major-version 22) + (delete-dups (delq nil (delete "" suggestions))))) + (history-add-new-input nil) ; Do not automatically add default to history for empty input. + (input (read-from-minibuffer + (cond ((bmkp-string-match-p ":[ \t]*\\'" prompt) prompt) + (deflt (format "%s (default %s): " prompt + (query-replace-descr deflt))) + (t (format "%s: " prompt))) + nil nil nil (or history 'regexp-history) suggestions t))) + (if (equal input "") + (or deflt input) ; Return the default value when the user enters empty input. + (prog1 input ; Add non-empty input to the history and return input. + (add-to-history (or history 'regexp-history) input))))) + + (defun bmkp-read-regexp (&optional prompt default history) ; Emacs 20-21 + "Read and return a string. +PROMPT defaults to \"Regexp: \". +Optional arg DEFAULT is a string that is returned when the user enters +empty input. It can also be a list of strings, of which only the +first is used. +Optional arg HISTORY is a symbol to use for the history list. If nil, +use `regexp-history'." + (unless prompt (setq prompt "Regexp: ")) + (when (consp default) (setq default (car default))) + (read-string (cond ((bmkp-string-match-p ":[ \t]*\\'" prompt) prompt) + (default (format "%s (default %s): " prompt + (mapconcat #'isearch-text-char-description default ""))) + (t (format "%s: " prompt))) + nil (or history 'regexp-history) default)))) + +;; Same as `icicle-propertize'. (Not used yet.) +;; +(defun bmkp-propertize (object &rest properties) + "Like `propertize', but for all Emacs versions. +If OBJECT is not a string, then use `prin1-to-string' to get a string." + (let ((new (if (stringp object) (copy-sequence object) (prin1-to-string object)))) + (add-text-properties 0 (length new) properties new) + new)) + +(defun bmkp-new-bookmark-default-names (&optional first-def) + "Return a list of default names (strings) for a new bookmark. +A non-nil optional arg FIRST-DEF is prepended to the list of names +described below. + +If the region is active and non-empty, then the first default name +\(other than FIRST-DEF) is the current buffer name followed by \": \" +and the region prefix (up to `bmkp-bookmark-name-length-max' chars). +The other names are as described below. + +Uses option `bmkp-new-bookmark-default-names' to come up with the +other names. To these names, `bookmark-current-bookmark' and +`bookmark-buffer-name' are appended, if available (non-nil). + +NOTE: For Emacs versions prior to Emacs 23, return only a single +default name, not a list of names. The name is the first in the list +of names described above for Emacs 23+." + (let ((defs (and first-def (list first-def))) + val) + (unless (and (< emacs-major-version 23) defs) ; Just use FIRST-DEF for Emacs < 23. + ;; If region is active, first default is its text, with buffer name prepended. + (when (and transient-mark-mode mark-active (> (region-end) (region-beginning))) + (let* ((regname (concat (buffer-name) ": " (buffer-substring (region-beginning) (region-end)))) + (defname (bmkp-replace-regexp-in-string + "\n" " " + (progn (save-excursion (goto-char (region-beginning)) + (skip-chars-forward " ") + (setq bookmark-yank-point (point))) + (substring regname 0 (min bmkp-bookmark-name-length-max + (length regname))))))) + (if (< emacs-major-version 23) (setq defs defname) (add-to-list 'defs defname)))) + ;; Names provided by option `bmkp-new-bookmark-default-names', + ;; plus `bookmark-current-bookmark' and `bookmark-buffer-name'. + (unless (and (< emacs-major-version 23) defs) + (catch 'bmkp-new-bookmark-default-names + (dolist (fn bmkp-new-bookmark-default-names) + (when (functionp fn) ; Be sure it is defined and is a function. + (setq val (funcall fn)) + (when (and (stringp val) (not (string= "" val))) + (setq val (bmkp-replace-regexp-in-string "\n" " " val)) + (if (> emacs-major-version 22) + (add-to-list 'defs val) + (throw 'bmkp-new-bookmark-default-names (setq defs val))))))) + (when (and (< emacs-major-version 23) (null defs)) + (setq defs (or bookmark-current-bookmark (bookmark-buffer-name)))) + (when (listp defs) + (when bookmark-current-bookmark (push bookmark-current-bookmark defs)) + (let ((buf (bookmark-buffer-name))) (when buf (push buf defs))) + (setq defs (nreverse defs))))) + defs)) + +(defun bmkp-bookmark-record-from-name (bookmark-name &optional noerror memp alist) + "Return the full bookmark (record) that corresponds to BOOKMARK-NAME. +BOOKMARK-NAME must be a string. If it has non-nil text property +`bmkp-full-record' then use that. Otherwise, look for the first +bookmark in ALIST that has the given name. + +Non-nil optional arg NOERROR means return nil if BOOKMARK-NAME does +not name a valid bookmark or is valid but is not in ALIST. If NOERROR +is nil then raise an error in this case. + +Non-nil optional arg MEMP means that if property `bmkp-full-record' is +available then look up its value (the full bookmark) in ALIST, testing +with `eq'. If that record is not in ALIST, return nil. + +Optional arg ALIST defaults to `bookmark-alist'." + (unless alist (setq alist bookmark-alist)) + (let ((full (get-text-property 0 'bmkp-full-record bookmark-name))) + (or (and full + (or (not memp) (memq full alist)) + full) + ;; Punt: return first matching bookmark in ALIST. + (if (fboundp 'assoc-string) ; Emacs 22+. Use `assoc-string' for its CASE-FOLD arg. + (assoc-string bookmark-name alist bookmark-completion-ignore-case) + (assoc bookmark-name alist)) + (and (not noerror) (error "No such bookmark in bookmark list: `%s'" bookmark-name))))) + +(defun bmkp-rename-for-marked-and-omitted-lists (old new) + "Replace OLD bookmark name with NEW in marked and omitted lists." + (when (bmkp-marked-bookmark-p old) + (setq bmkp-bmenu-marked-bookmarks (bmkp-delete-bookmark-name-from-list old + bmkp-bmenu-marked-bookmarks)) + (push new bmkp-bmenu-marked-bookmarks)) + (when (bmkp-omitted-bookmark-p old) + (setq bmkp-bmenu-omitted-bookmarks (bmkp-delete-bookmark-name-from-list old + bmkp-bmenu-omitted-bookmarks)) + (push new bmkp-bmenu-omitted-bookmarks))) + +(defun bmkp-get-bookmark-in-alist (bookmark &optional noerror alist) + "Return the full bookmark in ALIST that corresponds to BOOKMARK. +Return nil if there is none. +BOOKMARK is a bookmark name or a bookmark record. + +Non-nil optional arg NOERROR means return nil if BOOKMARK does not +represent a valid bookmark or is valid but is not in ALIST. If +NOERROR is nil then raise an error in this case. + +Optional arg ALIST defaults to `bookmark-alist'. + +Bookmark membership in ALIST is tested using `eq'. + +If BOOKMARK is a bookmark name instead of a full bookmark then return +what `bmkp-bookmark-record-from-name' with non-nil arg MEMP returns. + +This function is like `bookmark-get-bookmark', except that +`bookmark-get-bookmark' tests whether BOOKMARK is in `bookmark-alist' +only when it is a string (a bookmark name, not a full bookmark). When +BOOKMARK is a full bookmark `bookmark-get-bookmark' is thus not a test +for its existence, as is `bmkp-get-bookmark-in-alist'." + (cond ((consp bookmark) (and (memq bookmark (or alist bookmark-alist)) bookmark)) + ((stringp bookmark) (bmkp-bookmark-record-from-name bookmark noerror 'MEMP alist)) + (t (and (not noerror) (error "Invalid bookmark: `%s'" bookmark))))) + +(defun bmkp-default-bookmark-file () + "`bmkp-last-as-first-bookmark-file', or `bookmark-default-file' if nil." + (or bmkp-last-as-first-bookmark-file bookmark-default-file)) + +(defun bmkp-completing-read-bookmarks (&optional alist pred hist names-only-p use-nil-alist-p) + "Read bookmark names and return the bookmarks named as a list. +You are prompted for each bookmark name. Hit `RET' with empty input +to end. + +ALIST is the bookmark alist to use. It defaults to `bookmark-alist' +unless USE-NIL-ALIST-P is non-nil. + +NAMES-ONLY-P non-nil means return bookmark names, not full bookmarks. +If NAMES-ONLY-P is `lax' then completion is lax. + +USE-NIL-ALIST-P means do not default ALIST to `bookmark-alist': if +ALIST is nil there are no bookmark candidates, so just return nil." + (let ((bmks ()) + (bmk t)) + (if (and use-nil-alist-p (not alist)) + () + (while bmk + (setq bmk (bmkp-completing-read-1 "Bookmark (RET for each, empty input to finish)" + "" alist pred hist (eq names-only-p 'lax))) + (when (equal "" bmk) (setq bmk nil)) + (when (and bmk (not names-only-p)) (setq bmk (bmkp-get-bookmark-in-alist bmk 'NO-ERROR alist))) + (when bmk (push bmk bmks))) + (setq bmks (nreverse bmks)) + bmks))) + +(defun bmkp-completing-read-lax (prompt &optional default alist pred hist use-nil-alist-p) + "Read a bookmark name, prompting with PROMPT. +Like `bookmark-completing-read', but completion is lax (non-strict): +your input need not match any existing bookmark name. + +In addition: + * You can use `SPC' and `?' freely when typing the name. + * You can use `C-M-w' repeatedly to yank consecutive words from the + current buffer (see `bookmark-yank-word')." + (let ((orig-C-M-w (lookup-key minibuffer-local-completion-map (kbd "C-M-w"))) + (orig-C-M-u (lookup-key minibuffer-local-completion-map (kbd "C-M-u"))) + (orig-SPC (lookup-key minibuffer-local-completion-map (kbd "SPC"))) + (orig-qmark (lookup-key minibuffer-local-completion-map (kbd "?")))) + (unwind-protect + (progn (define-key minibuffer-local-completion-map (kbd "C-M-w") 'bookmark-yank-word) + (define-key minibuffer-local-completion-map (kbd "C-M-u") 'bookmark-insert-current-bookmark) + (unless (and (boundp 'icicle-mode) icicle-mode + (eq orig-SPC 'icicle-self-insert)) + (define-key minibuffer-local-completion-map (kbd "SPC") 'self-insert-command)) + (unless (and (boundp 'icicle-mode) icicle-mode + (eq orig-qmark 'icicle-self-insert)) + (define-key minibuffer-local-completion-map (kbd "?") 'self-insert-command)) + (bmkp-completing-read-1 prompt default alist pred hist 'LAX use-nil-alist-p)) + (define-key minibuffer-local-completion-map (kbd "C-M-w") orig-C-M-w) + (define-key minibuffer-local-completion-map (kbd "C-M-u") orig-C-M-u) + (define-key minibuffer-local-completion-map (kbd "SPC") orig-SPC) + (define-key minibuffer-local-completion-map (kbd "?") orig-qmark)))) + +(defun bmkp-completing-read-1 (prompt &optional default alist pred hist laxp use-nil-alist-p) + "Helper for functions that read a bookmark name with completion. +See `bookmark-completing-read' for the argument descriptions." + (bookmark-maybe-load-default-file) + (unless (or alist use-nil-alist-p) (setq alist bookmark-alist)) + (if (and (not laxp) + (listp last-nonmenu-event) + (or (eq t bmkp-menu-popup-max-length) + (and (integerp bmkp-menu-popup-max-length) (< (length alist) bmkp-menu-popup-max-length)))) + (bookmark-menu-popup-paned-menu + t prompt + (if bmkp-sort-comparer ; Test whether to sort, but always use `string-lessp'. + (sort (bookmark-all-names alist) 'string-lessp) + (bookmark-all-names alist))) + (let* ((icicle-delete-candidate-object (lambda (cand) ; For `S-delete' in Icicles. + (bookmark-delete (icicle-transform-multi-completion cand)))) + (icicle-bookmark-completing-p t) + (completion-ignore-case bookmark-completion-ignore-case) + (default (and (not (equal "" default)) default)) ; Treat "" like nil. + (default (if (and (consp default) (< emacs-major-version 23)) + (car default) + default)) + (prompt (concat prompt (if default + (format " (%s): " (if (consp default) + (car default) + default)) + ": "))) + (str (completing-read prompt alist pred (not laxp) nil + (or hist 'bookmark-history) default))) + str))) + +(defun bmkp-jump-1 (bookmark display-function &optional flip-use-region-p) + "Helper function for `bookmark-jump' commands. +BOOKMARK is a bookmark name or a bookmark record. +If it is a bookmark name then it is looked up in `bookmark-alist'. +If it is a record then it is NOT looked up (need not belong). +If it is or has a name that has non-nil property `bmkp-full-record', +then use the bookmark in `bookmark-alist' that is the value of that +property. Raise no error if it has no name. + +DISPLAY-FUNCTION as in `bmkp-jump'. Passed to `bookmark--jump-via'. +Non-nil optional arg FLIP-USE-REGION-P means temporarily flip the + value of `bmkp-use-region'." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (unless bookmark (error "No bookmark specified")) + (run-hooks 'bmkp-before-jump-hook) + (bookmark-maybe-historicize-string (bmkp-bookmark-name-from-record bookmark)) + (let ((bmkp-use-region (if flip-use-region-p (not bmkp-use-region) bmkp-use-region))) + (bookmark--jump-via bookmark display-function))) + +(defun bmkp-select-buffer-other-window (buffer) + "Select BUFFER in another window. +If `bmkp-other-window-pop-to-flag' is non-nil, then use +`pop-to-buffer'. Otherwise, use `switch-to-buffer-other-window'." + (if bmkp-other-window-pop-to-flag (pop-to-buffer buffer t) (switch-to-buffer-other-window buffer))) + +(defun bmkp-maybe-save-bookmarks (&optional same-count-p) + "Increment save counter and maybe save `bookmark-alist'. +Non-nil optional arg SAME-COUNT-P means do not increment +`bookmark-alist-modification-count'." + (unless same-count-p (setq bookmark-alist-modification-count (1+ bookmark-alist-modification-count))) + (when (bookmark-time-to-save-p) (bookmark-save))) + +;;;###autoload (autoload 'bmkp-annotate-bookmark "bookmark+") +(defun bmkp-annotate-bookmark (bookmark) ; Bound to `C-x x a a' + "Annotate BOOKMARK. Pop up a buffer to add or edit the annotation. +Interactively, this is the same as using command +`bookmark-edit-annotation' with a prefix arg. You are prompted for +the bookmark name. Command `bookmark-edit-annotation' can be more +convenient for editing an existing annotation, because you choose +among only the already annotated bookmarks, not all bookmarks. + +Non-interactively, BOOKMARK is a bookmark name or a bookmark record." + (interactive (list (bookmark-completing-read "Annotate bookmark" (bmkp-default-bookmark-name)))) + (pop-to-buffer (generate-new-buffer-name "*Bookmark Annotation Compose*")) + (bookmark-insert-annotation bookmark) + (bookmark-edit-annotation-mode) + (setq bookmark-annotation-name bookmark)) + +;;;###autoload (autoload 'bmkp-annotate-bookmark-this-file/buffer "bookmark+") +(defun bmkp-annotate-bookmark-this-file/buffer (bookmark) ; Bound to `C-x x a b' + "Annotate an existing bookmark in this file or buffer. +You are prompted for the name of a bookmark here, with completion." + (interactive + (let ((alist (bmkp-this-file/buffer-alist-only))) + (list (bookmark-completing-read (format "%s annotation for bookmark" + (if current-prefix-arg "Add or edit" "Edit")) + (or (and (fboundp 'bmkp-bookmarks-lighted-at-point) + (bmkp-bookmarks-lighted-at-point)) + (bmkp-default-bookmark-name alist)) + alist + nil + nil + (not current-prefix-arg))))) + (bookmark-edit-annotation bookmark)) + +;;;###autoload (autoload 'bmkp-annotate-all-bookmarks-this-file/buffer "bookmark+") +(defun bmkp-annotate-all-bookmarks-this-file/buffer () ; Bound to `C-x x a B' + "Pop up annotation-editing buffer for each bookmark in this file/buffer." + (interactive) + (dolist (bmk (bmkp-this-file/buffer-alist-only)) + (bookmark-edit-annotation bmk))) + +;;;###autoload (autoload 'bmkp-show-this-annotation-read-only "bookmark+") +(defun bmkp-show-this-annotation-read-only () + "Switch to `Show Bookmark Annotation' mode for this annotation. +That is, switch from edit mode to read-only mode." + (interactive) + (unless (eq major-mode 'bookmark-edit-annotation-mode) + (error "Buffer is not in `Edit Bookmark Annotation' mode")) + (if (not (or (not (buffer-modified-p)) (y-or-n-p "Annotation was modified. Lose changes?"))) + (message "OK, canceled - use `C-c C-c' if you want to save changes") + (let* ((bmk (bmkp-get-bookmark bookmark-annotation-name 'NOERROR)) + (bname (bookmark-name-from-full-record bmk)) + (ann (and bmk (bookmark-get-annotation bmk))) + (obuf (current-buffer))) + (unless bname (error "No such bookmark: `%s'" bmk)) + (bmkp--pop-to-buffer-same-window (format "*`%s' Annotation*" bname)) + (let ((buffer-read-only nil) ; Because buffer might already exist, in view mode. + (buf-modified-p (buffer-modified-p))) + (delete-region (point-min) (point-max)) + (insert (concat "Annotation for bookmark '" bname "':\n\n")) + ;; Use `font-lock-ignore' property from library `font-lock+.el', because Org mode + ;; uses font-lock, which would otherwise wipe out the highlighting added here. + (add-text-properties (line-beginning-position -1) (line-end-position 1) + '(face bmkp-heading + font-lock-ignore t)) + (insert ann) + (set-buffer-modified-p buf-modified-p)) + (goto-char (point-min)) + (bookmark-show-annotation-mode) + (when (fboundp 'fit-frame-if-one-window) (fit-frame-if-one-window)) + (setq bookmark-annotation-name bmk) + (kill-buffer obuf)))) + +;;;###autoload (autoload 'bmkp-edit-this-annotation "bookmark+") +(defun bmkp-edit-this-annotation () + "Switch to `Edit Bookmark Annotation' mode for this annotation. +That is, switch from read-only mode to edit mode." + (interactive) + (unless (eq major-mode 'bookmark-show-annotation-mode) + (error "Buffer is not in `Show Bookmark Annotation' mode")) + (let* ((bmk (bmkp-get-bookmark bookmark-annotation-name 'NOERROR)) + (bname (bookmark-name-from-full-record bmk)) + (obuf (current-buffer))) + (unless bname (error "No such bookmark: `%s'" bmk)) + (bmkp--pop-to-buffer-same-window (generate-new-buffer-name "*Bookmark Annotation Compose*")) + (let ((buf-modified-p (buffer-modified-p))) + (bookmark-insert-annotation bname) + (set-buffer-modified-p buf-modified-p)) + (bookmark-edit-annotation-mode) + (when (fboundp 'fit-frame-if-one-window) (fit-frame-if-one-window)) + (setq bookmark-annotation-name bmk) + (kill-buffer obuf))) + +;;;###autoload (autoload 'bmkp-copy-bookmark "bookmark+") +(defalias 'bmkp-copy-bookmark 'bmkp-clone-bookmark) +;;;###autoload (autoload 'bmkp-clone-bookmark "bookmark+") +(defun bmkp-clone-bookmark (bookmark &optional clone confirm-overwrite-p) + ; Bound to `C-x x 2' (`M-n' in bookmark list) + "Duplicate BOOKMARK to produce a clone. +The clone name is the same as BOOKMARK, but with \"<2>\" appended. +With a prefix arg you are instead prompted for the clone name. + +When called from Lisp: + * BOOKMARK is a bookmark name or a bookmark record. + * Optional CLONE is the clone name. + * Optional non-nil CONFIRM-OVERWRITE-P means prompt to confirm overwriting an existing bookmark." + (interactive + (let* ((orig (bookmark-completing-read "Clone bookmark" (bmkp-default-bookmark-name))) + ;; Remove any `bmkp-full-record' property from name. + (_IGNORE (remove-text-properties 0 (length orig) '(bmkp-full-record nil) orig)) + (default (concat orig "<2>")) + (new (if current-prefix-arg + (bmkp-completing-read-lax "Clone name" default) + default))) + (while (equal orig new) + (setq new (bmkp-completing-read-lax "Clone name (must be different)" default))) + ;; Remove any `bmkp-full-record' property from name. + (remove-text-properties 0 (length new) '(bmkp-full-record nil) new) + (list orig new t))) + (let ((orig-bmk (bmkp-get-bookmark bookmark)) + (new-bmk (bmkp-get-bookmark clone 'NO-ERROR))) + (when (and new-bmk confirm-overwrite-p) + (unless (yes-or-no-p "Another bookmark with that name already exists. Overwrite it? ") + (error "OK; canceled"))) + (setq new-bmk (copy-sequence orig-bmk)) + ;; Get rid of old bookmark name, which might have property `bmkp-full-record'. + ;; Need to do that before calling `bookmark-store'. + (setcar new-bmk clone) + (bookmark-store clone (cdr new-bmk) nil) ; (Puts `bmkp-full-record' on name.) + (setq bookmark-current-bookmark clone) + (if (and (get-buffer bmkp-bmenu-buffer) (get-buffer-window (get-buffer bmkp-bmenu-buffer) 0)) + (with-current-buffer (get-buffer bmkp-bmenu-buffer) + (bmkp-refresh-menu-list clone)) + (bookmark-bmenu-surreptitiously-rebuild-list)) + (bmkp-maybe-save-bookmarks))) + +;;;###autoload (autoload 'bmkp-edit-bookmark-name-and-location "bookmark+") +(defun bmkp-edit-bookmark-name-and-location (bookmark &optional edit-record-p) + ; Bound to `C-x x r' (`r' in bookmark list) + "Edit BOOKMARK's name and location, and maybe save them. +Return a list of the new bookmark name and new location. +BOOKMARK is a bookmark name or a bookmark record. + +Without a prefix arg, you are prompted for the new bookmark name and + the new location name. When entering the new names you can use + completion against existing names. This completion is lax, so you + can easily edit an existing name. See `bookmark-set' for particular + keys available during this input. + +With a prefix arg, edit the complete bookmark record (the + internal, Lisp form)." + (interactive + (list (bookmark-completing-read (concat "Edit " (and current-prefix-arg "internal record for ") + "bookmark") + (bmkp-default-bookmark-name)) + current-prefix-arg)) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark)) + (if edit-record-p + (bmkp-edit-bookmark-record bookmark) + (let* ((bmk-name (bmkp-bookmark-name-from-record bookmark)) + (bmk-location (bookmark-prop-get bookmark 'location)) + (bmk-urlp (and bmk-location + (require 'ffap nil t) + (ffap-url-p bmk-location))) + (bmk-filename (bookmark-get-filename bmk-name)) + (bmk-buffname (or (bmkp-get-buffer-name bookmark) + (bookmark-prop-get bookmark 'buffer))) + (new-bmk-name (bmkp-completing-read-lax + "New bookmark name" bmk-name)) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (new-location + (cond (bmk-location + (cond ((not bmk-urlp) (read-string "New location: ")) + ((and (featurep 'w3m) (bmkp-w3m-bookmark-p bmk-name)) + (w3m-input-url "New URL: " bmk-location)) + ((and (fboundp 'bmkp-eww-bookmark-p) (bmkp-eww-bookmark-p bmk-name)) + (read-string "New URL: ")) + ((require 'ffap) (ffap-read-file-or-url "New URL: " bmk-location)) + (t (read-string "New location: ")))) + (bmk-filename + (if (and (featurep 'w3m) + (bmkp-w3m-bookmark-p bmk-name)) + (w3m-input-url "New url: " bmk-filename) + (read-file-name + "New file name (location): " + (and bmk-filename + (file-name-directory bmk-filename)) + bmk-filename))) + (bmk-buffname + (read-buffer "New location: " bmk-buffname)) + (t ; No current location. + (read-string "New location: ")))) + ;; $$$$$$ Should we change a W3M bookmark that uses `filename' to use `location' instead? + (changed-bmk-name-p (and (not (equal new-bmk-name "")) + (not (equal new-bmk-name bmk-name)))) + (changed-location-p (and bmk-location + (not (equal new-location "")) + (not (equal new-location bmk-location)))) + (changed-filename-p (and bmk-filename + (not (equal new-location "")) + (not (equal new-location bmk-filename)))) + (changed-buffname-p (and bmk-buffname + (not (equal new-location "")) + (not (equal new-location bmk-buffname)) + (not (and (fboundp 'bmkp-eww-bookmark-p) + (bmkp-eww-bookmark-p bookmark)))))) + (when (or changed-bmk-name-p changed-location-p changed-filename-p changed-buffname-p) + (when changed-bmk-name-p (bookmark-rename bmk-name new-bmk-name 'BATCHP)) + (when changed-location-p (bookmark-prop-set new-bmk-name 'location new-location)) + (when changed-filename-p (bookmark-set-filename new-bmk-name new-location)) + (when changed-buffname-p (bookmark-prop-set new-bmk-name 'buffer-name new-location)) + ;; Change location for Dired too, but not if different from original file name (e.g. a cons). + (let ((dired-dir (bookmark-prop-get new-bmk-name 'dired-directory))) + (when (and dired-dir (equal dired-dir bmk-filename)) + (bookmark-prop-set new-bmk-name 'dired-directory new-location))) + (bmkp-maybe-save-bookmarks) ; Maybe save automatically. + (when (and bookmark-alist-modification-count ; Did not save automatically. Ask user. + (y-or-n-p "Save changes? ")) + (bookmark-save)) + (list new-bmk-name new-location))))) + +(define-derived-mode bmkp-edit-bookmark-records-mode emacs-lisp-mode + "Edit Bookmark Records" + "Mode for editing a list of bookmark records, as in `bookmark-alist'. +When you finish editing, use \\\ +`\\[bmkp-edit-bookmark-record-send]' in the record-editing buffer." + :group 'bookmark-plus) + +;; This binding must be defined *after* the mode, so `bmkp-edit-bookmark-records-mode-map' is defined. +;; (Alternatively, we could use a `defvar' to define `bmkp-edit-bookmark-records-mode-map' before +;; calling `define-derived-mode'.) +(define-key bmkp-edit-bookmark-records-mode-map "\C-c\C-c" 'bmkp-edit-bookmark-records-send) + +(defvar bmkp-edit-bookmark-records-number 0 + "NUmber of bookmard records being edited.") + +;;;###autoload (autoload 'bmkp-edit-bookmark-records-send "bookmark+") +(defun bmkp-edit-bookmark-records-send (&optional msg-p) ; Bound to `C-c C-c' in records-editing buffer. + "Update `bookmark-alist' with buffer contents: a bookmark alist. +Lines beginning with `;;' are ignored. +Non-interactively, optional arg MSG-P means display progress messages. + +This assumes that the bookmarks in the buffer are the marked bookmarks +in `*Bookmark List*'. That is, it assumes that the buffer was created +by `bmkp-bmenu-edit-marked' (`\\\\[bmkp-bmenu-edit-marked]' in `*Bookmark List*')." + (interactive "p") + (unless (eq major-mode 'bmkp-edit-bookmark-records-mode) + (error "Not in `bmkp-edit-bookmark-records-mode'")) + (when msg-p (message "Reading edited bookmarks...")) + (let* ((editbuf (current-buffer)) + (orig-bmks (bmkp-marked-bookmarks-only)) + (edited-bookmarks ()) + (read-error-msg + (catch 'bmkp-edit-bookmark-records-send + (setq edited-bookmarks (condition-case err + (save-excursion (goto-char (point-min)) (read (current-buffer))) + (error (throw 'bmkp-edit-bookmark-records-send + (error-message-string err))))) + (unless orig-bmks (error "No marked bookmarks now - edits must correspond to currently marked")) + (cond ((not (listp edited-bookmarks)) + (throw 'bmkp-edit-bookmark-records-send "Not a list of bookmarks")) + ((not (= (length edited-bookmarks) bmkp-edit-bookmark-records-number)) + (throw 'bmkp-edit-bookmark-records-send + (format "Need %d bookmarks, but there seem to be %d" + bmkp-edit-bookmark-records-number (length edited-bookmarks))))) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save only after `dolist' and update. + (dolist (edited-bmk edited-bookmarks) + (unless (and (consp edited-bmk) (stringp (car edited-bmk))) ; Sanity check. + (throw 'bmkp-edit-bookmark-records-send (format "Invalid bookmark: `%s'" edited-bmk))) + (let ((bname (bmkp-bookmark-name-from-record edited-bmk)) + (data (bmkp-bookmark-data-from-record edited-bmk))) + ;; Put the full bookmark on its name as property `bmkp-full-record'. + ;; Do this regardless of Emacs version and `bmkp-propertize-bookmark-names-flag'. + ;; If it needs to be stripped, that will be done when saving. + (put-text-property 0 (length bname) 'bmkp-full-record edited-bmk bname) + ;; Update the original bookmark (same cons cell) with what's in the edited version. + (setcar (car orig-bmks) bname) + (setcdr (car orig-bmks) data) + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq (car orig-bmks) bmkp-modified-bookmarks) + (setq bmkp-modified-bookmarks (cons (car orig-bmks) bmkp-modified-bookmarks))) + (setq orig-bmks (cdr orig-bmks)))) + ;; Update using modified ORIG-BMKS. + (setq bmkp-bmenu-marked-bookmarks (mapcar #'bmkp-bookmark-name-from-record + bmkp-modified-bookmarks) + bmkp-sorted-alist (bmkp-sort-omit bookmark-alist) + bookmark-alist-modification-count (1+ bookmark-alist-modification-count))) + nil))) + (if (stringp read-error-msg) + (if msg-p (message "%s --> edit and try again" read-error-msg) (error read-error-msg)) + (when (get-buffer editbuf) (kill-buffer editbuf)) + (bmkp-refresh/rebuild-menu-list + (and (= 1 (length edited-bookmarks)) (car edited-bookmarks)) ; Only one, so we belong on its line. + (not msg-p))))) + +(define-derived-mode bmkp-edit-bookmark-record-mode emacs-lisp-mode + "Edit Bookmark Record" + "Mode for editing an internal bookmark record. +When you finish editing, use \\\ +`\\[bmkp-edit-bookmark-record-send]' in the record-editing buffer." + :group 'bookmark-plus) + +;; This binding must be defined *after* the mode, so `bmkp-edit-bookmark-record-mode-map' is defined. +;; (Alternatively, we could use a `defvar' to define `bmkp-edit-bookmark-record-mode-map' before +;; calling `define-derived-mode'.) +(define-key bmkp-edit-bookmark-record-mode-map "\C-c\C-c" 'bmkp-edit-bookmark-record-send) + +;;;###autoload (autoload 'bmkp-edit-bookmark-record "bookmark+") +(defun bmkp-edit-bookmark-record (bookmark) ; Bound to `C-x x E'. + "Edit the full record (the Lisp sexp) for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +When you finish editing, use \\\ +`\\[bmkp-edit-bookmark-record-send]' in the record-editing buffer. +The current bookmark list is then updated to reflect your edits." + (interactive (list (bookmark-completing-read "Edit Lisp record for bookmark" (bmkp-default-bookmark-name)))) + (bookmark-maybe-load-default-file) + (setq bmkp-edit-bookmark-orig-record (bmkp-get-bookmark-in-alist bookmark)) + (let* ((bmk-copy (copy-sequence bmkp-edit-bookmark-orig-record)) ; Shallow copy + (bname (bmkp-bookmark-name-from-record bmk-copy)) + (bufname (format "*Edit Record for Bookmark `%s'*" bname))) + (set-text-properties 0 (length bname) nil bname) ; Strip properties from (copied) name string. + (bookmark-maybe-historicize-string bname) + (bmkp-with-output-to-plain-temp-buffer bufname + (princ + (substitute-command-keys + (concat ";; Edit the Lisp record for bookmark\n;;\n" + ";; `" bname "'\n;;\n" + ";; Type \\\ +`\\[bmkp-edit-bookmark-record-send]' when done.\n;;\n"))) + ;; (let ((print-circle t)) (pp bmk)) ; $$$$$$ Binding should not really be needed now. + (pp bmk-copy) + (goto-char (point-min))) + (pop-to-buffer bufname) + (buffer-enable-undo) + (with-current-buffer (get-buffer bufname) (bmkp-edit-bookmark-record-mode)))) + +;;;###autoload (autoload 'bmkp-edit-bookmark-record-send "bookmark+") +(defun bmkp-edit-bookmark-record-send (&optional msg-p) ; Bound to `C-c C-c' in record-editing buffer. + "Update `bookmark-alist' with buffer contents: a bookmark record. +Lines beginning with `;;' are ignored. +Non-interactively, optional arg MSG-P means display progress messages." + (interactive "p") + (unless (eq major-mode 'bmkp-edit-bookmark-record-mode) + (error "Not in `bmkp-edit-bookmark-record-mode'")) + (unless (and (boundp 'bmkp-edit-bookmark-orig-record) (consp bmkp-edit-bookmark-orig-record)) + (error "Lost original bookmark record - try edit command again")) + (when msg-p (message "Reading edited bookmark...")) + (let* ((editbuf (current-buffer)) + (bmk-name nil) + (read-error-msg + (catch 'bmkp-edit-bookmark-record-send + (let ((edited-bmk + (condition-case err + (save-excursion (goto-char (point-min)) (read (current-buffer))) + (error (throw 'bmkp-edit-bookmark-record-send (error-message-string err)))))) + (unless (and (consp edited-bmk) (stringp (car edited-bmk))) + (throw 'bmkp-edit-bookmark-record-send (format "Invalid bookmark: `%s'" edited-bmk))) + (let ((bname (bmkp-bookmark-name-from-record edited-bmk)) + (data (bmkp-bookmark-data-from-record edited-bmk))) + ;; Put the full bookmark on its name as property `bmkp-full-record'. + ;; Do this regardless of Emacs version and `bmkp-propertize-bookmark-names-flag'. + ;; If it needs to be stripped, that will be done when saving. + (put-text-property 0 (length bname) 'bmkp-full-record edited-bmk bname) + ;; Update the original bookmark with what's in the edited version. + (setcar bmkp-edit-bookmark-orig-record bname) + (setcdr bmkp-edit-bookmark-orig-record data) + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bmkp-edit-bookmark-orig-record bmkp-modified-bookmarks) + (setq bmkp-modified-bookmarks (cons bmkp-edit-bookmark-orig-record + bmkp-modified-bookmarks))) + (setq bmk-name bname)) ; Save for bookmark-list display, below. + (setq bmkp-sorted-alist (bmkp-sort-omit bookmark-alist) + bookmark-alist-modification-count (1+ bookmark-alist-modification-count))) + nil))) + (if (stringp read-error-msg) + (if msg-p (message "%s --> edit and try again" read-error-msg) (error read-error-msg)) + (when (get-buffer editbuf) (kill-buffer editbuf)) + (bmkp-refresh/rebuild-menu-list bmk-name (not msg-p))) + (unless read-error-msg + (setq bmkp-edit-bookmark-orig-record nil)))) ; Reset it, but keep it if error so can try again. + +;;;###autoload (autoload 'bmkp-edit-bookmark-record-file/buffer "bookmark+") +(defun bmkp-edit-bookmark-record-file/buffer (bookmark) ; Not bound + "Edit the full record (the Lisp sexp) of a bookmark in this buffer. +You are prompted for the name of a bookmark here, with completion." + (interactive + (let ((alist (bmkp-this-file/buffer-alist-only))) + (list (bookmark-completing-read (format "%s annotation for bookmark" + (if current-prefix-arg "Add or edit" "Edit")) + (or (and (fboundp 'bmkp-bookmarks-lighted-at-point) + (bmkp-bookmarks-lighted-at-point)) + (bmkp-default-bookmark-name alist)) + alist + nil + nil + (not current-prefix-arg))))) + (bmkp-edit-bookmark-record bookmark)) + +;;; ;;;###autoload (autoload 'bmkp-edit-all-bookmark-records-this-file/buffer "bookmark+") +;;; (defun bmkp-edit-all-bookmark-records-this-file/buffer () ; Not bound +;;; "Pop up a record-editing buffer for each bookmark in this file/buffer." +;;; (interactive) +;;; (dolist (bmk (bmkp-this-file/buffer-alist-only)) +;;; (bmkp-edit-bookmark-record bmk))) + +(define-derived-mode bmkp-edit-tags-mode emacs-lisp-mode + "Edit Bookmark Tags" + "Mode for editing bookmark tags. +When you have finished composing, type \\[bmkp-edit-tags-send]." + :group 'bookmark-plus) + +;; This binding must be defined *after* the mode, so `bmkp-edit-tags-mode-map' is defined. +;; (Alternatively, we could use a `defvar' to define `bmkp-edit-tags-mode-map' before +;; calling `define-derived-mode'.) +(define-key bmkp-edit-tags-mode-map "\C-c\C-c" 'bmkp-edit-tags-send) + +;;;###autoload (autoload 'bmkp-edit-tags "bookmark+") +(defun bmkp-edit-tags (bookmark) ; Bound to `C-x x t e' + "Edit BOOKMARK's tags, and maybe save the result. +The edited value must be a list each of whose elements is either a + string or a cons whose key is a string. +BOOKMARK is a bookmark name or a bookmark record." + (interactive (list (bookmark-completing-read "Edit tags for bookmark" (bmkp-default-bookmark-name)))) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark)) + (let* ((btags (bmkp-get-tags bookmark)) + (bmkname (bmkp-bookmark-name-from-record bookmark)) + (edbuf (format "*Edit Tags for Bookmark `%s'*" bmkname))) + (setq bmkp-return-buffer (current-buffer)) + (bmkp-with-output-to-plain-temp-buffer edbuf + (princ + (substitute-command-keys + (concat ";; Edit tags for bookmark\n;;\n;; \"" bmkname "\"\n;;\n" + ";; The edited value must be a list each of whose elements is\n" + ";; either a string or a cons whose key is a string.\n;;\n" + ";; DO NOT MODIFY THESE COMMENTS.\n;;\n" + ";; Type \\`\\[bmkp-edit-tags-send]' when done.\n\n"))) + (let ((print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag)) + (pp btags)) + (goto-char (point-min))) + (pop-to-buffer edbuf) + (buffer-enable-undo) + (with-current-buffer (get-buffer edbuf) (bmkp-edit-tags-mode)))) + +;;;###autoload (autoload 'bmkp-edit-tags-send "bookmark+") +(defun bmkp-edit-tags-send (&optional batchp) + "Use buffer contents as the internal form of a bookmark's tags. +DO NOT MODIFY the header comment lines, which begin with `;;'." + (interactive) + (unless (eq major-mode 'bmkp-edit-tags-mode) (error "Not in `bmkp-edit-tags-mode'")) + (let (bname) + (unwind-protect + (let (tags bmk) + (goto-char (point-min)) + (unless (search-forward ";; Edit tags for bookmark\n;;\n;; ") + (error "Missing header in edit buffer")) + (unless (stringp (setq bname (read (current-buffer)))) + (error "Bad bookmark name in edit-buffer header")) + (unless (setq bmk (bmkp-get-bookmark-in-alist bname 'NOERROR)) + (error "No such bookmark: `%s'" bname)) + (goto-char (point-min)) + (setq tags (read (current-buffer))) + (unless (listp tags) (error "Tags sexp is not a list of strings or an alist with string keys")) + (bookmark-prop-set bmk 'tags tags) + (setq bname (bmkp-bookmark-name-from-record bmk)) + (bmkp-record-visit bmk batchp) + (bmkp-refresh/rebuild-menu-list bname batchp) + (bmkp-maybe-save-bookmarks) + (unless batchp (message "Updated bookmark file with edited tags"))) + (kill-buffer (current-buffer))) + (when bmkp-return-buffer + (pop-to-buffer bmkp-return-buffer) + (when (equal (buffer-name (current-buffer)) bmkp-bmenu-buffer) + (bmkp-bmenu-goto-bookmark-named bname))))) + +(defun bmkp-record-visit (bookmark &optional batchp) + "Update the data recording a visit to BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +This increments the `visits' entry and sets the `time' entry to the +current time. If either an entry is not present, it is added (with 0 +value for `visits'). +With non-nil optional arg BATCHP, do not rebuild the menu list. + +Although this function modifies BOOKMARK, it does not increment +`bookmark-alist-modification-count', and it does not add BOOKMARK to +`bmkp-modified-bookmarks'. This is so that simply recording the visit +does not count toward needing to save or showing BOOKMARK as modified." + (let ((vis (bookmark-prop-get bookmark 'visits)) + (bmkp-modified-bookmarks bmkp-modified-bookmarks)) + (bookmark-prop-set bookmark 'visits (if vis (1+ vis) 0)) + (bookmark-prop-set bookmark 'time (current-time)) + (unless batchp (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P)) + (let ((bookmark-save-flag nil)) (bmkp-maybe-save-bookmarks 'SAME-COUNT-P)))) + +(defun bmkp-default-bookmark-name (&optional alist) + "Default bookmark name. See option `bmkp-default-bookmark-name'. +Non-nil ALIST means return nil unless the default names a bookmark in +ALIST." + (let ((bname (if (equal (buffer-name (current-buffer)) bmkp-bmenu-buffer) + (bookmark-bmenu-bookmark) + (if (fboundp 'bmkp-default-lighted) + (if (eq 'highlighted bmkp-default-bookmark-name) + (or (bmkp-default-lighted) bookmark-current-bookmark) + (or bookmark-current-bookmark (bmkp-default-lighted))) + bookmark-current-bookmark)))) + (when (consp bname) (setq bname (car bname))) ; Since `bmkp-default-lighted' can return a list of names. + (when (and bname alist) + (setq bname (bmkp-bookmark-name-from-record (bmkp-bookmark-record-from-name + bname 'NOERROR 'MEMP alist)))) + bname)) + +(defun bmkp-buffer-names () + "Buffer names used by existing bookmarks that really have buffers. +This excludes buffers for bookmarks such as desktops that are not +really associated with a buffer." + (let ((bufs ()) + buf) + (dolist (bmk bookmark-alist) + (when (and (not (bmkp-desktop-bookmark-p bmk)) + (not (bmkp-bookmark-file-bookmark-p bmk)) + (not (bmkp-sequence-bookmark-p bmk)) + (not (bmkp-function-bookmark-p bmk)) + (not (bmkp-variable-list-bookmark-p bmk)) + (setq buf (bmkp-get-buffer-name bmk))) + (add-to-list 'bufs buf))) + bufs)) + +(defun bmkp-file-names () + "The absolute file names used by the existing bookmarks. +This excludes the pseudo file name `bmkp-non-file-filename'." + (let ((files ()) + file) + (dolist (bmk bookmark-alist) + (when (and (setq file (bookmark-get-filename bmk)) (not (equal file bmkp-non-file-filename))) + (add-to-list 'files file))) + files)) + +;;;###autoload (autoload 'bmkp-bookmark-set-confirm-overwrite "bookmark+") +(defun bmkp-bookmark-set-confirm-overwrite (&optional name parg interactivep) ; Bound `C-x r m', `C-x x c m'. + "Set a bookmark named NAME, then run `bmkp-after-set-hook'. +This is the same as `bookmark-set', except that with no prefix arg you +are asked to confirm overwriting an existing bookmark of the same +NAME." + (interactive (list nil current-prefix-arg t)) + (let ((bmkp-bookmark-set-confirms-overwrite-p t)) + (call-interactively #'bookmark-set))) + +;;;###autoload (autoload 'bmkp-send-bug-report "bookmark+") +(defun bmkp-send-bug-report () ; Not bound + "Send a bug report about a Bookmark+ problem." + (interactive) + (browse-url (format (concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +Bookmark+ bug: \ +&body=Describe bug below, using a precise recipe that starts with `emacs -Q' or `emacs -q'. \ +Be sure to mention the `Update #' from header of the particular Bookmark+ file header.\ +%%0A%%0AEmacs version: %s") + (emacs-version)))) + +;;;###autoload (autoload 'bmkp-toggle-bookmark-set-refreshes "bookmark+") +(defun bmkp-toggle-bookmark-set-refreshes () ; Not bound + "Toggle whether `bookmark-set' refreshes `bookmark-alist' as last filtered. +Add/remove `bmkp-refresh-latest-bookmark-list' to/from +`bmkp-after-set-hook'. +\(Applies also to command `bmkp-bookmark-set-confirm-overwrite'.)" + (interactive) + (if (member 'bmkp-refresh-latest-bookmark-list bmkp-after-set-hook) + (remove-hook 'bmkp-after-set-hook 'bmkp-refresh-latest-bookmark-list) + (add-hook 'bmkp-after-set-hook 'bmkp-refresh-latest-bookmark-list))) + +(defun bmkp-refresh-latest-bookmark-list () + "Refresh `bmkp-latest-bookmark-alist' to reflect `bookmark-alist'." + (setq bmkp-latest-bookmark-alist (if bmkp-bmenu-filter-function + (funcall bmkp-bmenu-filter-function) + bookmark-alist))) + +;;;###autoload (autoload 'bmkp-toggle-saving-menu-list-state "bookmark+") +(defun bmkp-toggle-saving-menu-list-state () ; Bound to `C-M-~' in bookmark list + "Toggle the value of option `bmkp-bmenu-state-file'. +Tip: You can use this before quitting Emacs, to not save the state. +If the initial value of `bmkp-bmenu-state-file' is nil, then this +command has no effect." + (interactive) + (unless (or bmkp-last-bmenu-state-file bmkp-bmenu-state-file) + (error "Cannot toggle: initial value of `bmkp-bmenu-state-file' is nil")) + (setq bmkp-last-bmenu-state-file (prog1 bmkp-bmenu-state-file + (setq bmkp-bmenu-state-file bmkp-last-bmenu-state-file))) + (message (if bmkp-bmenu-state-file + "Autosaving of bookmark list state is now ON" + "Autosaving of bookmark list state is now OFF"))) + +;;;###autoload (autoload 'bmkp-save-menu-list-state "bookmark+") +(defun bmkp-save-menu-list-state (&optional msg-p) ; Used in `bookmark-exit-hook-internal'. + "Save menu-list state, unless not saving or list has not yet been shown. +The state is saved to the value of `bmkp-bmenu-state-file'. +Non-interactively, optional arg MSG-P means display progress messages." + (interactive "p") + (when (and (not bmkp-bmenu-first-time-p) bmkp-bmenu-state-file) + (when msg-p (message "Saving bookmark-list display state...")) + (let ((config-list + `((last-sort-comparer . ,bmkp-sort-comparer) + (last-reverse-sort-p . ,bmkp-reverse-sort-p) + (last-reverse-multi-sort-p . ,bmkp-reverse-multi-sort-p) + (last-latest-bookmark-alist . ,(bmkp-maybe-unpropertize-bookmark-names + bmkp-latest-bookmark-alist)) + (last-bmenu-omitted-bookmarks . ,(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-omitted-bookmarks 'COPY)) + (last-bmenu-marked-bookmarks . ,(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-marked-bookmarks 'COPY)) + (last-bmenu-filter-function . ,bmkp-bmenu-filter-function) + (last-bmenu-filter-pattern . ,bmkp-bmenu-filter-pattern) + (last-bmenu-title . ,bmkp-bmenu-title) + (last-bmenu-bookmark . ,(and (get-buffer bmkp-bmenu-buffer) + (with-current-buffer + (get-buffer bmkp-bmenu-buffer) + (bmkp-maybe-unpropertize-string + (bookmark-bmenu-bookmark) 'COPY)))) + ;; Use `copy-sequence' here just in case, to avoid circular references when + ;; `bmkp-propertize-bookmark-names-flag' is nil. + (last-specific-buffer . ,(copy-sequence bmkp-last-specific-buffer)) + (last-specific-file . ,(copy-sequence bmkp-last-specific-file)) + (last-bmenu-toggle-filenames . ,bookmark-bmenu-toggle-filenames) + (last-bmenu-before-hide-marked-alist . ,(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-before-hide-marked-alist 'COPY)) + (last-bmenu-before-hide-unmarked-alist . ,(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-before-hide-unmarked-alist 'COPY)) + (last-bookmark-file . ,(copy-sequence + (convert-standard-filename + (expand-file-name + bmkp-current-bookmark-file)))) + (last-previous-bookmark-file . ,(and bmkp-last-bookmark-file + (copy-sequence + (convert-standard-filename + (expand-file-name + bmkp-last-bookmark-file)))))))) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect bmkp-bmenu-state-file)) + (goto-char (point-min)) + (delete-region (point-min) (point-max)) + (let ((print-length nil) + (print-level nil) + (print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag) + (version-control (case bookmark-version-control + ((nil) nil) + (never 'never) + (nospecial version-control) + (t t))) + (require-final-newline t) + (errorp nil)) + (pp config-list (current-buffer)) + (condition-case nil + (write-file bmkp-bmenu-state-file) + (file-error + (setq errorp t) + ;; Do NOT raise error - used in `bookmark-exit-hook-internal'. (Need to be able to exit.) + (let ((msg (format "CANNOT WRITE FILE `%s'" bmkp-bmenu-state-file))) + (if (fboundp 'display-warning) + (display-warning 'bookmark-plus msg) + (message msg) + (sit-for 4))))) + (kill-buffer (current-buffer)) + (when (and msg-p (not errorp)) (message "Saving bookmark-list display state...done"))))))) + +;;;###autoload (autoload 'bmkp-toggle-saving-bookmark-file "bookmark+") +(defun bmkp-toggle-saving-bookmark-file (&optional msg-p) ; Bound to `M-~' in bookmark list + "Toggle the value of option `bookmark-save-flag'. +If the initial value of `bookmark-save-flag' is nil, then this +command has no effect. +Non-interactively, non-nil MSG-P means display a status message." + (interactive "p") + (unless (or bmkp-last-save-flag-value bookmark-save-flag) + (error "Cannot toggle: initial value of `bookmark-save-flag' is nil")) + ;; One of the two vars should be nil. If both are non-nil, set `*-last-*' to nil before toggling. + (when (and bmkp-last-save-flag-value bookmark-save-flag) (setq bmkp-last-save-flag-value nil)) + (setq bmkp-last-save-flag-value (prog1 bookmark-save-flag + (setq bookmark-save-flag bmkp-last-save-flag-value))) + (when msg-p (message (if bookmark-save-flag + "Autosaving of current bookmark file is now ON" + "Autosaving of current bookmark file is now OFF")))) + +;; Same as `read-from-whole-string' (called `thingatpt--read-from-whole-string' starting with Emacs 25) +;; in library `thingatpt.el'. +;; +(defun bmkp-read-from-whole-string (string) + "Read a Lisp expression from STRING. +Raise an error if the entire string was not used." + (let* ((read-data (read-from-string string)) + (more-left (condition-case nil + ;; The call to `ignore' suppresses a compiler warning. + (progn (ignore (read-from-string (substring string (cdr read-data)))) + t) + (end-of-file nil)))) + (if more-left (error "Can't read whole string") (car read-data)))) + +;;;###autoload (autoload 'bmkp-jump-to-list "bookmark+") +(defun bmkp-jump-to-list (bookmark + &optional position msgp) ; Bound globally to `C-x j C-j', `C-x x C-j' + "Jump to BOOKMARK entry in `*Bookmark List*'. +You are prompted for BOOKMARK (a bookmark name). +If you use library `bookmark+-lit.el': + * The defaults for BOOKMARK are the lighted bookmarks at point. + * A prefix arg means only lighted bookmarks at point are candidates." + (interactive (let* ((litp (fboundp 'bmkp-bookmarks-lighted-at-point)) + (lbmks (and litp (bmkp-bookmarks-lighted-at-point (point) nil 'MSG))) + (bmk (bookmark-completing-read (if current-prefix-arg "Lighted bookmark" "Bookmark") + (and litp (if current-prefix-arg (car lbmks) lbmks)) + (and current-prefix-arg lbmks)))) + (list bmk (point) t))) + (pop-to-buffer (get-buffer-create bmkp-bmenu-buffer)) + (bookmark-bmenu-list) + (bmkp-bmenu-goto-bookmark-named (setq bmkp-last-bmenu-bookmark bookmark))) + +;;;###autoload (autoload 'bmkp-make-function-bookmark "bookmark+") +(defun bmkp-make-function-bookmark (bookmark-name function &optional msg-p) ; Bound globally to `C-x x c F'. + "Create a bookmark that invokes FUNCTION when \"jumped\" to. +You are prompted for the bookmark name and the name of the function. +But with a prefix arg the last keyboard macro defined is used instead +of prompting you for a function. + +Returns the new bookmark (internal record). + +Non-interactively, non-nil optional arg MSG-P means display a status +message." + (interactive (let ((icicle-unpropertize-completion-result-flag t)) + (list (bmkp-completing-read-lax "Bookmark") + (if (and current-prefix-arg last-kbd-macro) + (read-kbd-macro last-kbd-macro 'NEED-VECTOR) + (completing-read "Function: " obarray 'functionp)) + 'MSG))) + (unless (or (functionp function) (vectorp function)) + (setq function (bmkp-read-from-whole-string function))) ; Convert name to symbol. + (bookmark-store bookmark-name `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT 0 nil 'NO-REGION) + (function . ,function) + (handler . bmkp-jump-function)) + nil nil (not msg-p)) + (let ((new (bmkp-bookmark-record-from-name bookmark-name 'NOERROR))) + (unless (memq new bmkp-latest-bookmark-alist) + (setq bmkp-latest-bookmark-alist (cons new bmkp-latest-bookmark-alist))) + (bookmark-bmenu-surreptitiously-rebuild-list (not msg-p)) + new)) + +;;;###autoload (autoload 'bmkp-set-dired-bookmark-for-files "bookmark+") +(defun bmkp-set-dired-bookmark-for-files (bookmark-name dired-name to-add &optional switches msg-p) + "Create a Dired bookmark for a set of files and directories. +You are prompted for the Dired buffer name and the file or directory +entries to include. With a prefix arg, you are also prompted for the +`ls' switches. + +Use `C-g' when done choosing file and directory names. Any directory +names you choose this way are included as single entries in the +listing - the directory contents are not included. To instead include +the contents of a directory, use a glob pattern: put `/*' after the +directory name. + +You need library `Dired+' for this command." + (interactive + (let* ((_IGNORE (unless (require 'dired+ nil t) + (error "You need library `Dired+' for this command"))) + (current-prefix-arg (if current-prefix-arg 0 -1)) + (all (diredp-dired-union-interactive-spec + "add files/dirs " + 'NO-DIRED-BUFS + 'READ-EXTRA-FILES-P))) + (list (bmkp-completing-read-lax "Bookmark") (nth 0 all) (nth 3 all) (nth 2 all) 'MSG))) + (bmkp-make-function-bookmark + bookmark-name + `(lambda () (diredp-add-to-dired-buffer ',dired-name ',to-add ',switches)) + msg-p)) + +(when (boundp 'grep-history) ; Emacs 26+ + (defun bmkp-set-grep-command-bookmark (bookmark-name &optional grep-cmd msg-p) + "Create a bookmark to run the last grep command. +With a prefix arg, you are prompted for the grep command to record, + with lax completion against your previous `grep' inputs in this + session." + (interactive + (let ((parg current-prefix-arg)) + (unless grep-history (error "Emacs command `grep' has not yet been run")) + (list (bmkp-completing-read-lax "Bookmark") + (and parg + (completing-read "Grep command: " + grep-history nil t nil 'grep-history (car grep-history))) + 'MSG))) + (setq grep-cmd (or grep-cmd (car grep-history))) + (unless (stringp grep-cmd) (error "Emacs command `grep' has not yet been run")) + (bmkp-make-function-bookmark bookmark-name + `(lambda () (funcall #'grep ,grep-cmd)) + msg-p))) + +;;;###autoload (autoload 'bmkp-revert-bookmark-file "bookmark+") +(defun bmkp-revert-bookmark-file (&optional msg-p) ; Same as `C-u g' in bookmark list (but not bound). + "Revert to the bookmarks in the current bookmark file. +You are asked for confirmation. + +This DISCARDS all modifications to bookmarks and the bookmark list +\(e.g. added/deleted bookmarks) since the last bookmark-file save. +IOW, it reloads the bookmark file, overwriting the current bookmark +list. This also removes any markings and omissions. + +This has the same effect as using `C-u \\\\[bmkp-bmenu-refresh-menu-list]' in \ +buffer `*Bookmark List*'. +To refresh the display from the current bookmark list instead of the +bookmark file, use just `\\[bmkp-bmenu-refresh-menu-list]' (no `C-u'). + +Non-interactively, non-nil MSG-P means display a status message." + (interactive "p") + (when (and msg-p (not (yes-or-no-p (format "Revert to bookmarks saved in file `%s'? " + bmkp-current-bookmark-file)))) + (error "OK - canceled")) + (bookmark-load bmkp-current-bookmark-file 'OVERWRITE msg-p) ; Do not let `bookmark-load' ask to save. + (bmkp-refresh/rebuild-menu-list nil (not msg-p))) + +;;;###autoload (autoload 'bmkp-switch-bookmark-file "bookmark+") +(defun bmkp-switch-bookmark-file (file &optional batchp) ; Not bound and not used in the code now. + "Switch to a different bookmark file, FILE. +Return FILE. Interactively, you are prompted for FILE. +Replace all bookmarks in the current bookmark list with those from the +newly loaded FILE. Bookmarks are subsequently saved to FILE. + +Optional arg BATCHP is passed to `bookmark-load'." + (interactive + (list (let* ((std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + bookmark-default-file + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Switch to bookmark file: " + (or (file-name-directory default) "~/") + default + t)))) ; Require that the file exist. + (bookmark-load file t batchp)) ; Treat it interactively, if this command is called interactively. + +;;;###autoload (autoload 'bmkp-switch-to-last-bookmark-file "bookmark+") +(defun bmkp-switch-to-last-bookmark-file (&optional batchp) ; Not bound to key, but effectively `C-u C-x x L' + "Switch back to the last-used bookmark file. +Replace all currently existing bookmarks with those newly loaded from +the last-used file. Swap the values of `bmkp-last-bookmark-file' and +`bmkp-current-bookmark-file'. + +Optional arg BATCHP is passed to `bookmark-load'." + (interactive) + (bookmark-load (or bmkp-last-bookmark-file (bmkp-default-bookmark-file)) + t batchp)) ; Treat it interactively, if this command is called interactively. + +;;;###autoload (autoload 'bmkp-switch-bookmark-file-create "bookmark+") +(defun bmkp-switch-bookmark-file-create (file &optional switch-to-lastp batchp) + ; Bound to `C-x x L', (`L' in bookmark list) + "Switch to bookmark file FILE, creating it as empty if it does not exist. +With a prefix arg, switch to the last bookmark file used. +Otherwise, you are prompted for FILE. + +Replace all bookmarks in the current bookmark list with those from the +newly loaded file. Bookmarks are subsequently saved to that file. + +If there is no file with the name you provide (FILE), then create a +new, empty bookmark file with that name and use that from now on. +This empties the bookmark list. Interactively, you are required to +confirm this. + +Return the newly current bookmark file. + +When called from Lisp: +* FILE is the bookmark-file name or nil (meaning use the last one). +* Non-nil BATCHP is passed to `bookmark-load'." + (interactive + (if current-prefix-arg + (list nil current-prefix-arg) + (list (let* ((std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + bookmark-default-file + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Switch to bookmark file: " + (or (file-name-directory default) "~/") + default)) + nil))) + (if (not switch-to-lastp) + (let ((empty-p nil)) + (if (file-readable-p file) +;;; (if (or batchp (y-or-n-p (format "CONFIRM: `%s' as the current bookmark file? " file))) +;;; (bookmark-load file t batchp) +;;; (error "OK, canceled")) + (bookmark-load file t batchp) ; Treat it interactively, if this command is called interactively. + (setq empty-p t) + (when (and (not batchp) + (not (y-or-n-p (format "Create and use NEW, EMPTY bookmark file `%s'? " file)))) + (error "OK - canceled")) + (bmkp-empty-file file) + (bookmark-load file t batchp)) ; Treat it interactively, if this command is called interactively. + (unless batchp (message "Bookmark file is now %s`%s'" (if empty-p "EMPTY file " "") file))) + (bmkp-switch-to-last-bookmark-file batchp) + (setq file bmkp-current-bookmark-file)) + file) + +;;;###autoload (autoload 'bmkp-switch-to-bookmark-file-this-file/buffer "bookmark+") +(defun bmkp-switch-to-bookmark-file-this-file/buffer (file &optional batchp) ; Bound to `C-x x C-l' + "Switch to a bookmark file for bookmarks in this file or buffer. +If visiting a file, the bookmarks are ‘bmkp-this-file-alist-only’. +Otherwise, they are ‘bmkp-this-buffer-alist-only’. + +If there are unsaved bookmarks in the current bookmark list you are +first prompted to save it. + +You are then prompted for the bookmark file to switch to, for +bookmarks only for this file/buffer." + (interactive + (list (let* ((std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + bookmark-default-file + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Switch to bookmark file for bookmarks here: " + (or (and default (file-name-directory default)) "~/") + default)))) + (bmkp-switch-bookmark-file-create file)) + +(defun bmkp-read-bookmark-file-name (&optional prompt dir default-filename require-match) + "Read and return an (absolute) bookmark file name. +PROMPT is the prompt to use (default: \"Use bookmark file: \"). +The other args are the same as for `read-file-name'." + (let ((insert-default-directory t) + (icicle-unpropertize-completion-result-flag t)) ; For `read-file-name'. + (expand-file-name + (read-file-name (or prompt "Use bookmark file: ") dir default-filename require-match)))) + +(defun bmkp-read-bookmark-file-default () + "A default value for `bmkp-read-bookmark-file-name' DEFAULT-FILENAME arg. +A value to use if you want a default and there is none better." + (if (and (> emacs-major-version 22) + (not (bmkp-same-file-p "~/.emacs.bmk" bookmark-default-file))) + (list "~/.emacs.bmk" bookmark-default-file) + "~/.emacs.bmk")) + +;;;###autoload (autoload 'bmkp-empty-file "bookmark+") +(defun bmkp-empty-file (file &optional confirmp) ; Bound to `C-x x 0' + "Empty the bookmark file FILE, or create FILE (empty) if it does not exist. +In either case, FILE will become an empty bookmark file. Return FILE. + +NOTE: If FILE already exists and you confirm emptying it, no check is + made that it is in fact a bookmark file before emptying it. + It is simply replaced by an empty bookmark file and saved. + +This does NOT also make FILE the current bookmark file. To do that, +use `\\[bmkp-switch-bookmark-file-create]' (`bmkp-switch-bookmark-file-create'). + +Interactively, and non-interactively if optional arg CONFIRMP is +non-nil, require confirmation if the file already exists." + (interactive (list (let ((icicle-unpropertize-completion-result-flag t)) + (read-file-name "Create empty bookmark file: " "~/")) + t)) + (setq file (expand-file-name file)) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (bookmark-maybe-load-default-file) + (when (and confirmp (file-exists-p file) + (not (y-or-n-p (format "CONFIRM: Empty the existing file `%s'? " file)))) + (error "OK - canceled")) + (let ((bookmark-alist ())) + (bookmark-write-file file nil (if (file-exists-p file) + "Emptying bookmark file `%s'..." + "Creating new, empty bookmark file `%s'..."))) + file) + +(defun bmkp-write-alist-bookmarks-to-file (alist file &optional addp) + "Write bookmarks in ALIST to FILE. +By default, replace FILE with only the ALIST bookmarks. +Non-nil ADDP means just add the bookmarks to those already in +FILE (updating them if already present)." + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (let ((bookmark-save-flag nil) ; Inhibit auto-saving for the duration. + (bookmark-alist bookmark-alist) + (bookmark-alist-modification-count bookmark-alist-modification-count) + imported) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) + (if (file-exists-p file) + (bookmark-maybe-upgrade-file-format) + (delete-region (point-min) (point-max)) ; In case a find-file hook inserted a header etc. + (if (boundp 'bookmark-file-coding-system) ; Insert timestamp and an empty bookmark list. + (bookmark-insert-file-format-version-stamp bookmark-file-coding-system) ; Emacs 25.2+ + (bookmark-insert-file-format-version-stamp)) + (insert "(\n)")) + (let ((blist (bookmark-alist-from-buffer))) + (unless (listp blist) (error "Invalid bookmark list in file `%s'" file)) + (setq bookmark-alist blist) ; Bookmarks in FILE + (setq imported (bookmark-import-new-list alist nil 'RETURN-BMKS)) + (unless (and (zerop (nth 0 imported)) (zerop (nth 1 imported))) + (bookmark-write-file file)))))) + +;;;###autoload (autoload 'bmkp-save-bookmarks-this-file/buffer "bookmark+") +(defun bmkp-save-bookmarks-this-file/buffer (file &optional addp batchp) ; Bound to `C-x x C-s' + "Save bookmarks defined for the current file/buffer to FILE. +If visiting a file, the bookmarks are ‘bmkp-this-file-alist-only’. +Otherwise, they are ‘bmkp-this-buffer-alist-only’. + +You are prompted for FILE, the bookmark file to save to. + +By default, replace FILE with only the bookmarks for the current +file/buffer. With a prefix arg, just add the bookmarks to those +already in FILE (updating them if already present). + +This does NOT make FILE the current bookmark file. To do that, use +`bmkp-switch-to-bookmark-file-this-file/buffer'." + (interactive + (list (let* ((std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + bookmark-default-file + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "File to save bookmarks in: " + (or (and default (file-name-directory default)) "~/") + default)) + current-prefix-arg)) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (when (and (not (file-readable-p file)) + (not batchp) + (not (y-or-n-p (format "Save to NEW, EMPTY bookmark file `%s'? " file)))) + (error "OK - canceled")) + (bmkp-write-alist-bookmarks-to-file (bmkp-this-file/buffer-alist-only) file addp)) + +;;;###autoload (autoload 'bmkp-crosshairs-highlight "bookmark+") +(defun bmkp-crosshairs-highlight () ; Not bound + "Highlight point with crosshairs temporarily. +Do not highlight if either the region is active or +`bmkp-crosshairs-flag' is nil. + +You can add this to hook `bookmark-after-jump-hook'. +You need library `crosshairs.el' to use this command." + (interactive) + (when (and bmkp-crosshairs-flag (> emacs-major-version 21)) ; No-op for Emacs 20-21. + (unless (condition-case nil (require 'crosshairs nil t) (error nil)) + (error "You need library `crosshairs.el' to use this command")) + (unless mark-active + (let ((crosshairs-overlay-priority (and (boundp 'bmkp-light-priorities) + (1+ (apply #'max + (mapcar #'cdr bmkp-light-priorities)))))) + (crosshairs-highlight))))) + +;;;###autoload (autoload 'bmkp-choose-navlist-from-bookmark-list "bookmark+") +(defun bmkp-choose-navlist-from-bookmark-list (bookmark &optional alist) ; Bound to `C-x x B' + "Choose a bookmark-list bookmark and set the bookmark navigation list. +The navigation-list variable, `bmkp-nav-alist', is set to the list of +bookmarks that would be displayed by `bookmark-bmenu-list' (`C-x r l') +for the chosen bookmark-list bookmark, sorted and filtered as +appropriate. + +Instead of choosing a bookmark-list bookmark, you can choose the +pseudo-bookmark `CURRENT *Bookmark List*'. The bookmarks used for the +navigation list are those that would be currently shown in the +`*Bookmark List*' (even if the list is not currently displayed). + +BOOKMARK is a bookmark name or a bookmark record. +Optional arg ALIST is an alternative alist of bookmarks to use." + (interactive + (let ((bookmark-alist (cons (bmkp-current-bookmark-list-state) (bmkp-bookmark-list-alist-only)))) + (list (bmkp-read-bookmark-for-type "bookmark-list" bookmark-alist nil nil + 'bmkp-bookmark-list-history "Choose ") + bookmark-alist))) + (setq alist (or alist (cons (bmkp-current-bookmark-list-state) (bmkp-bookmark-list-alist-only)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR alist))) + (let ((state (let ((bookmark-alist alist)) (bookmark-prop-get bookmark 'bookmark-list)))) + (let ((bname (bmkp-bookmark-name-from-record bookmark)) + (bmkp-sort-comparer (cdr (assq 'last-sort-comparer state))) + (bmkp-reverse-sort-p (cdr (assq 'last-reverse-sort-p state))) + (bmkp-reverse-multi-sort-p (cdr (assq 'last-reverse-multi-sort-p state))) + (bmkp-bmenu-omitted-bookmarks (cdr (assq 'last-bmenu-omitted-bookmarks state))) + (bmkp-bmenu-filter-function (cdr (assq 'last-bmenu-filter-function state))) + (bmkp-bmenu-filter-pattern (or (cdr (assq 'last-bmenu-filter-pattern state)) "")) + (bmkp-bmenu-title (cdr (assq 'last-bmenu-title state))) + (bookmark-bmenu-toggle-filenames (cdr (assq 'last-bmenu-toggle-filenames state)))) + (setq bmkp-nav-alist (bmkp-sort-omit + (if bmkp-bmenu-filter-function + (funcall bmkp-bmenu-filter-function) + (if (string= "CURRENT *Bookmark List*" bname) + (or bmkp-latest-bookmark-alist bookmark-alist) + bookmark-alist)) + (and (not (eq bmkp-bmenu-filter-function + 'bmkp-omitted-alist-only)) + bmkp-bmenu-omitted-bookmarks)) + bmkp-current-nav-bookmark (car bmkp-nav-alist)) + (message "Bookmark navigation list is now %s" + (if (and (string= "CURRENT *Bookmark List*" bname) (not (get-buffer bmkp-bmenu-buffer))) + "the global bookmark list" + (format "`%s'" bname)))))) + +(defun bmkp-current-bookmark-list-state () + "Pseudo-bookmark for the current `*Bookmark List*' state." + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (cons "CURRENT *Bookmark List*" (bmkp-make-bookmark-list-record))) + +;;; This function is used in macro `bmkp-define-history-variables', so +;;; its definition is also in `bookmark+-mac.el'. +;;; +(defun bmkp-types-alist () + "Alist of bookmark types used by `bmkp-jump-to-type'. +Keys are bookmark type names. Values are corresponding history variables. +The alist is used in commands such as `bmkp-jump-to-type'." + (let ((entries ())) + (mapatoms + (lambda (sym) + (let ((name (symbol-name sym))) + (when (string-match "\\`bmkp-\\(.+\\)-alist-only\\'" name) + (push (cons (match-string 1 name) + (intern (format "bmkp-%s-history" (match-string 1 name)))) + entries))))) + entries)) + +;;;###autoload (autoload 'bmkp-choose-navlist-of-type "bookmark+") +(defun bmkp-choose-navlist-of-type (type) ; Bound to `C-x x :' + "Set the bookmark navigation list to the bookmarks of a type you choose. +The pseudo-type `any' sets the navigation list to all bookmarks. +This sets variable `bmkp-nav-alist'." + (interactive + (let* ((completion-ignore-case t) + (icicle-unpropertize-completion-result-flag t) + (type (completing-read "Type: " + (cons '("any" . bookmark-history) + (bmkp-types-alist)) + nil t nil nil "any"))) + (list type))) + (setq bmkp-nav-alist (if (equal "any" type) + bookmark-alist + (funcall (intern (format "bmkp-%s-alist-only" type))))) + (unless bmkp-nav-alist (error "No bookmarks")) + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist)) + (message "Bookmark navigation list is now %s" + (if (equal "any" type) "all bookmarks" (format "for type `%s'" type)))) + +(defun bmkp-autonamed-bookmark-p (bookmark &optional buffer) + "Return non-nil if BOOKMARK is an autonamed bookmark for BUFFER. +If BUFFER is nil then any buffer is OK. +BOOKMARK is a bookmark name or a bookmark record. +BUFFER, if non-nil, is a buffer or a buffer name." + (unless (stringp bookmark) (setq bookmark (bmkp-bookmark-name-from-record bookmark))) + (when (bufferp buffer) (setq buffer (buffer-name buffer))) + (let ((nargs 0) + (start 0)) + (save-match-data + (while (string-match "%\\([+ #-0]+\\)?\\([0-9]+\\)?\\([.][0-9]+\\)?[BsSdoxXefgc]" + bmkp-autoname-format + start) + (setq nargs (1+ nargs) + start (match-end 0)))) + (bmkp-string-match-p + (apply #'format + (bmkp-format-spec bmkp-autoname-format `((?B . ,(if buffer (regexp-quote buffer) ".*")))) + (make-list nargs ".*")) + bookmark))) + +(defun bmkp-format-spec (format specification) + "Like `format-spec', but respect standard `format' %-sequences. +%-sequences specified in SPECIFICATION are handled per `format-spec' +Any standard `format' %-sequences not specified in SPECIFICATION are +left as is. + +This is also more general than `format-spec', in that the full format +of a %-sequence is supported: `%character'. +`format-spec' does not support precision>, and it supports only the +flags `-' and `0'." + (with-temp-buffer + (insert format) + (goto-char (point-min)) + (while (search-forward "%" nil t) + (cond ((eq (char-after) ?%) (delete-char 1)) ; Quoted percent sign. + ((looking-at "\\([+ #-0]+\\)?\\([0-9]+\\)?\\([.][0-9]+\\)?\\([a-zA-Z]\\)") + (let* ((num (match-string 2)) + (spec (string-to-char (match-string 4))) + (val (assq spec specification))) + (if (not val) + ;; Ignore standard format chars that are not redefined by SPECIFICATION. + (unless (memq (string-to-char (match-string 4)) '(?s ?S ?d ?o ?x ?X ?e ?f ?g ?c)) + (error "Invalid format character: `%%%c'" spec)) + (setq val (cdr val)) + (let ((text (format (concat "%" num "s") val))) ; Pad result to desired length. + (insert-and-inherit text) ; Insert first, to preserve text properties. + (delete-region (+ (match-beginning 0) (length text)) ; Delete specifier body. + (+ (match-end 0) (length text))) + (delete-region (1- (match-beginning 0)) ; Delete percent sign. + (match-beginning 0)))))) + (t (error "Invalid format string")))) + (buffer-string))) + +(defun bmkp-autonamed-this-buffer-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an autonamed bookmark for this buffer." + (unless (stringp bookmark) (setq bookmark (bmkp-bookmark-name-from-record bookmark))) + (bmkp-autonamed-bookmark-p bookmark (buffer-name))) + +(defun bmkp-autonamed-bookmark-for-buffer-p (bookmark buffer-name) + "Return non-nil if BOOKMARK is an autonamed bookmark for BUFFER. +BOOKMARK is a bookmark name or a bookmark record. +BUFFER-NAME is a string matching the buffer-name part of an autoname. +This does not check the `buffer-name' entry of BOOKMARK. It checks +only the buffer indicated by the bookmark name." + (unless (stringp bookmark) (setq bookmark (bmkp-bookmark-name-from-record bookmark))) + (bmkp-autonamed-bookmark-p bookmark buffer-name)) + +(defun bmkp-update-autonamed-bookmark (bookmark) + "Update the name and position of the autonamed BOOKMARK at point. +Return the updated BOOKMARK: If input was a bookmark name, then return + then new name, else the new (full) bookmark. +It is a good idea to set BOOKMARK to the result of this call. +BOOKMARK is a bookmark name or a bookmark record." + (let ((namep (stringp bookmark))) + (setq bookmark (bmkp-get-bookmark bookmark)) + (bookmark-set-position bookmark (point)) + ;; Autonamed bookmarks do not have regions. Update `end-position' to be the same as `position'. + (when (bmkp-get-end-position bookmark) + (bookmark-prop-set bookmark 'end-position (point))) + (let ((newname (funcall bmkp-autoname-bookmark-function (point)))) + (bookmark-rename (bmkp-bookmark-name-from-record bookmark) newname 'BATCHP) + (bmkp-refresh/rebuild-menu-list (bmkp-bookmark-name-from-record bookmark)) ; So display new name. + (bmkp-maybe-save-bookmarks)) + (if namep (bmkp-bookmark-name-from-record bookmark) bookmark))) ; Return updated bookmark or name. + +;;;###autoload (autoload 'bmkp-this-file/buffer-bmenu-list "bookmark+") +(defun bmkp-this-file/buffer-bmenu-list () ; Bound to `C-x x ,' + "Show the bookmark list just for bookmarks for the current file/buffer. +If visiting a file, this is `bmkp-this-file-bmenu-list'. Otherwise, +this is `bmkp-this-buffer-bmenu-list'." + (interactive) + (if (buffer-file-name) (bmkp-this-file-bmenu-list) (bmkp-this-buffer-bmenu-list))) + +;;;###autoload (autoload 'bmkp-this-file-bmenu-list "bookmark+") +(defun bmkp-this-file-bmenu-list () + "Show the bookmark list just for bookmarks for the current file. +Set `bmkp-last-specific-file' to the current file name. +If the current buffer is not visiting a file, prompt for the file name." + (interactive) + (unless bookmark-alist (bookmark-maybe-load-default-file)) ; Just to be sure. + (let ((orig-last-spec-file bmkp-last-specific-file) + (orig-filter-fn bmkp-bmenu-filter-function) + (orig-title bmkp-bmenu-title) + (orig-latest-alist bmkp-latest-bookmark-alist)) + (condition-case err + (progn + (setq bmkp-last-specific-file (or (buffer-file-name) + (let ((icicle-unpropertize-completion-result-flag t)) + (read-file-name "File: "))) + bmkp-bmenu-filter-function 'bmkp-last-specific-file-alist-only + bmkp-bmenu-title (format "File `%s' Bookmarks" bmkp-last-specific-file)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function)) + (bmkp-bmenu-state-file nil)) ; Prevent restoring saved state. + (unless bookmark-alist (error "No bookmarks for file `%s'" bmkp-last-specific-file)) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (pop-to-buffer (get-buffer-create bmkp-bmenu-buffer)) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) + (format "Only bookmarks for file `%s' are shown" + bmkp-last-specific-file))) + (raise-frame)) + (error (progn (setq bmkp-last-specific-file orig-last-spec-file + bmkp-bmenu-filter-function orig-filter-fn + bmkp-bmenu-title orig-title + bmkp-latest-bookmark-alist orig-latest-alist) + (error "%s" (error-message-string err))))))) + +;;;###autoload (autoload 'bmkp-this-buffer-bmenu-list "bookmark+") +(defun bmkp-this-buffer-bmenu-list () + "Show the bookmark list just for bookmarks for the current buffer. +Set `bmkp-last-specific-buffer' to the current buffer name." + (interactive) + (unless bookmark-alist (bookmark-maybe-load-default-file)) + (let ((orig-last-spec-buf bmkp-last-specific-buffer) + (orig-filter-fn bmkp-bmenu-filter-function) + (orig-title bmkp-bmenu-title) + (orig-latest-alist bmkp-latest-bookmark-alist)) + (condition-case err + (progn + (setq bmkp-last-specific-buffer (buffer-name) + bmkp-bmenu-filter-function 'bmkp-last-specific-buffer-alist-only + bmkp-bmenu-title (format "Buffer `%s' Bookmarks" + bmkp-last-specific-buffer)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function)) + (bmkp-bmenu-state-file nil)) ; Prevent restoring saved state. + (unless bookmark-alist (error "No bookmarks for buffer `%s'" + bmkp-last-specific-buffer)) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (pop-to-buffer (get-buffer-create bmkp-bmenu-buffer)) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) + (format "Only bookmarks for buffer `%s' are shown" + bmkp-last-specific-buffer))) + (raise-frame)) + (error (progn (setq bmkp-last-specific-buffer orig-last-spec-buf + bmkp-bmenu-filter-function orig-filter-fn + bmkp-bmenu-title orig-title + bmkp-latest-bookmark-alist orig-latest-alist) + (error "%s" (error-message-string err))))))) + +;;;###autoload (autoload 'bmkp-navlist-bmenu-list "bookmark+") +(defun bmkp-navlist-bmenu-list () ; Bound to `C-x x N' + "Show the bookmark list just for bookmarks from the navigation list." + (interactive) + (unless bmkp-nav-alist + (bookmark-maybe-load-default-file) + (setq bmkp-nav-alist bookmark-alist) + (unless bmkp-nav-alist (error "No bookmarks")) + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist)) + (message "Bookmark navigation list is now the GLOBAL bookmark list") (sit-for 2)) + (let ((orig-title bmkp-bmenu-title) + (orig-latest-alist bmkp-latest-bookmark-alist)) + (condition-case err + (progn + (setq bmkp-bmenu-title "Current Navlist Bookmarks") + (let ((bookmark-alist bmkp-nav-alist) + (bmkp-bmenu-state-file nil)) ; Prevent restoring saved state. + (unless bookmark-alist (error "No bookmarks")) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (pop-to-buffer (get-buffer-create bmkp-bmenu-buffer)) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) + "Only bookmarks for the navigation list are shown")) + (raise-frame)) + (error (progn (setq bmkp-bmenu-title orig-title + bmkp-latest-bookmark-alist orig-latest-alist) + (error "%s" (error-message-string err))))))) + +(defun bmkp-completing-read-buffer-name (&optional no-default-p) + "Read the name of a buffer associated with a bookmark. +The candidates are the buffers in `bmkp-buffer-names'. +Non-nil NO-DEFAULT-P means provide no default value. Used when + called in a loop, to let the user exit using empty input. +If NO-DEFAULT-P is nil, then the default is the current buffer's name, + or the value of `bmkp-last-specific-buffer' if the current buffer has + no bookmarks." + (bookmark-maybe-load-default-file) + (let ((icicle-unpropertize-completion-result-flag t)) + (completing-read "Buffer: " (mapcar #'list (bmkp-buffer-names)) nil t nil 'buffer-name-history + (and (not no-default-p) + (if (member (buffer-name) (bmkp-buffer-names)) + (buffer-name) + bmkp-last-specific-buffer))))) + +(defun bmkp-completing-read-file-name (&optional no-default-p) + "Read the name of a file associated with a bookmark. +The candidates are the absolute file names in `bmkp-file-names'. +Non-nil NO-DEFAULT-P means provide no default value. Used when + called in a loop, to let the user exit using empty input. +If NO-DEFAULT-P is nil, then the default is the current buffer's file + name, if any, or the value of `bmkp-last-specific-file' if the + current buffer has no associated file or the file has no bookmarks." + (bookmark-maybe-load-default-file) + (let ((completion-ignore-case (if (boundp 'read-file-name-completion-ignore-case) + read-file-name-completion-ignore-case + (memq system-type + '(ms-dos windows-nt darwin cygwin)))) + (icicle-unpropertize-completion-result-flag t)) + (completing-read "File: " (mapcar #'list (bmkp-file-names)) nil t nil 'file-name-history + (and (not no-default-p) + (let ((file (buffer-file-name))) + (if (and file (member file (bmkp-file-names))) + file + bmkp-last-specific-file)))))) + +(defun bmkp-refresh/rebuild-menu-list (&optional bookmark no-msg-p) + "Refresh or rebuild buffer `*Bookmark List*'. +If the buffer is already displayed, call `bmkp-refresh-menu-list'. +Otherwise, call `bookmark-bmenu-surreptitiously-rebuild-list'. +Args are the same as for `bmkp-refresh-menu-list'." + (let ((bmklistbuf (get-buffer bmkp-bmenu-buffer))) + (if (and bmklistbuf (get-buffer-window bmklistbuf 0)) + (with-current-buffer bmklistbuf (bmkp-refresh-menu-list bookmark no-msg-p)) + (bookmark-bmenu-surreptitiously-rebuild-list no-msg-p)))) + +(defun bmkp-refresh-menu-list (&optional bookmark no-msg-p) + "Refresh (revert) the bookmark list (\"menu list\"). +This brings the displayed list up to date. It does not change the +current filtering or sorting of the displayed list. +Non-nil optional arg BOOKMARK means move cursor to BOOKMARK's line. +BOOKMARK is a bookmark name or a bookmark record. +Non-nil optional arg NO-MSG-P means do not show progress messages." + (let ((bookmark-alist (if bmkp-bmenu-filter-function + (funcall bmkp-bmenu-filter-function) + bookmark-alist))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (unless no-msg-p (message "Updating bookmark list...")) + (bookmark-bmenu-list bmkp-bmenu-filter-function) ; No filter function means start anew. + (when bookmark + (unless (stringp bookmark) (setq bookmark (bmkp-bookmark-name-from-record bookmark))) + (with-current-buffer (get-buffer bmkp-bmenu-buffer) + (bmkp-bmenu-goto-bookmark-named bookmark) + (let ((bmenu-win (get-buffer-window (current-buffer) 0))) + (when bmenu-win (set-window-point bmenu-win (point)))))) + (unless no-msg-p (message "Updating bookmark list...done")))) + +;;;###autoload (autoload 'bmkp-unomit-all "bookmark+") +(defun bmkp-unomit-all (&optional msg-p) ; Bound to `O U' in bookmark list + "Remove all bookmarks from the list of omitted bookmarks. +After this, all bookmarks are available for display. +Non-interactively, non-nil optional arg MSG-P means display a status +message." + (interactive "p") + (unless bmkp-bmenu-omitted-bookmarks (error "No omitted bookmarks to UN-omit")) + (when msg-p (message "UN-omitting ALL omitted bookmarks...")) + (let ((count 0)) + (dolist (bmk-name bmkp-bmenu-omitted-bookmarks) + (setq bmkp-bmenu-omitted-bookmarks (bmkp-delete-bookmark-name-from-list + bmk-name bmkp-bmenu-omitted-bookmarks) + count (1+ count))) + (bookmark-bmenu-surreptitiously-rebuild-list (not msg-p)) + (when msg-p (message "UN-omitted %d bookmarks" count))) + (when (equal (buffer-name (current-buffer)) bmkp-bmenu-buffer) (bmkp-bmenu-show-all)) + (when (and (fboundp 'fit-frame-if-one-window) (equal (buffer-name (current-buffer)) bmkp-bmenu-buffer)) + (fit-frame-if-one-window))) + + +;;(@* "Search-and-Replace Locations of Marked Bookmarks") +;; *** Search-and-Replace Locations of Marked Bookmarks *** + +(when (> emacs-major-version 22) + (defvar bmkp-isearch-bookmarks nil + "Bookmarks whose locations are to be incrementally searched.") + + (defun bmkp-isearch-next-bookmark-buffer (&optional bookmark wrap) + "Return the next buffer in a series of bookmark buffers. +Used as a value for `multi-isearch-next-buffer-function', for Isearch +of multiple bookmarks. + +Variable `bmkp-isearch-bookmarks' is a list of bookmarks. Each +bookmark in the list is visited by `bookmark--jump-via', and the +corresponding bookmark buffer is returned." + (let ((bookmarks (if isearch-forward bmkp-isearch-bookmarks (reverse bmkp-isearch-bookmarks)))) + (bookmark--jump-via + (if wrap + (car bookmarks) + (let ((this-bmk (catch 'bmkp-isearch-next-bookmark-buffer + (dolist (bmk bookmarks) + (when (if (bmkp-get-buffer-name bmk) + (equal (bmkp-get-buffer-name bmk) (buffer-name)) + (equal (bookmark-get-filename bmk) (buffer-file-name))) + (throw 'bmkp-isearch-next-bookmark-buffer bmk))) + (car bookmarks)))) + (cadr (member this-bmk bookmarks)))) + 'ignore) + (current-buffer))) + + (defun bmkp-isearch-bookmarks (bookmarks) + "Start multi-bookmark Isearch on BOOKMARKS." + (let ((multi-isearch-next-buffer-function 'bmkp-isearch-next-bookmark-buffer) + (bmkp-isearch-bookmarks bookmarks)) + (bookmark-jump (car bookmarks)) + (goto-char (if isearch-forward (point-min) (point-max))) + (isearch-forward))) + + (defun bmkp-isearch-bookmarks-regexp (bookmarks) + "Start multi-bookmark regexp Isearch on BOOKMARKS." + (let ((multi-isearch-next-buffer-function 'bmkp-isearch-next-bookmark-buffer) + (bmkp-isearch-bookmarks bookmarks)) + (bookmark-jump (car bookmarks)) + (goto-char (if isearch-forward (point-min) (point-max))) + (isearch-forward-regexp)))) + + +;;(@* "Tags") +;; *** Tags *** + +(defun bmkp-get-tags (bookmark) + "Return the `tags' entry for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (bookmark-prop-get bookmark 'tags)) + +(defalias 'bmkp-tagged-bookmark-p 'bmkp-get-tags) + +(defun bmkp-get-tag-value (bookmark tag) + "Return value of BOOKMARK's tag TAG. +BOOKMARK is a bookmark name or a bookmark record. +TAG is a string. +Return nil if BOOKMARK has no such TAG or if TAG has no value." + (assoc-default tag (bmkp-get-tags bookmark))) + +(defun bmkp-has-tag-p (bookmark tag) + "Return non-nil if BOOKMARK is tagged with TAG. +BOOKMARK is a bookmark name or a bookmark record. +TAG is a string." + (assoc-default tag (bmkp-get-tags bookmark) nil t)) + +;; NOT USED currently - we use `bmkp-read-tags-completing' instead. +(defun bmkp-read-tags () + "Read tags one by one, and return them as a list." + (let ((tag (read-string "Tag (RET for each, empty input to finish): ")) + (btags ())) + (while (not (string= "" tag)) + (push tag btags) + (setq tag (read-string "Tag: "))) + btags)) + +(defun bmkp-read-tag-completing (&optional prompt candidate-tags require-match update-tags-alist-p) + "Read a tag with completion, and return it as a string. +The candidate tags available are determined by option +`bmkp-tags-for-completion'. + +PROMPT is the prompt string. If nil, then use \"Tag: \". +CANDIDATE-TAGS is an alist of tags to use for completion. + If nil, then all tags from all bookmarks are used for completion. + The set of all tags is taken from variable `bmkp-tags-alist'. +REQUIRE-MATCH is passed to `completing-read'. +Non-nil UPDATE-TAGS-ALIST-P means update var `bmkp-tags-alist'." + (bookmark-maybe-load-default-file) + (let ((cand-tags (copy-sequence + (or candidate-tags + (and (not update-tags-alist-p) + bmkp-tags-alist) ; Use cached list. + (bmkp-tags-list)))) ; Update the cache. + (icicle-unpropertize-completion-result-flag t)) + (completing-read (or prompt "Tag: ") cand-tags nil require-match nil 'bmkp-tag-history))) + +(defun bmkp-read-tags-completing (&optional candidate-tags require-match update-tags-alist-p) + "Read tags with completion, and return them as a list of strings. +Read tags one by one, until you hit `RET' twice consecutively. + +CANDIDATE-TAGS is an alist of tags to use for completion. + If nil then the candidate tags are taken from variable + `bmkp-tags-alist'. +REQUIRE-MATCH is passed to `completing-read'. +Non-nil UPDATE-TAGS-ALIST-P means update var `bmkp-tags-alist', +determining the tags to use per option `bmkp-tags-for-completion'." + (bookmark-maybe-load-default-file) + (let ((cands ()) + (btags ()) + (prompt1 "Tag (RET for each, empty input to finish): ") + (prompt2 "Tag: ") + (icicle-unpropertize-completion-result-flag t) + tag old-tag) + ;; Make a new candidates alist, with just one entry per tag name. The original cdr is discarded. + (dolist (full-tag (or candidate-tags + (and (not update-tags-alist-p) bmkp-tags-alist) ; Use cached list. + (bmkp-tags-list))) + (add-to-list 'cands (list (if (consp full-tag) (car full-tag) full-tag)))) + (setq tag (completing-read prompt1 cands nil require-match nil 'bmkp-tag-history) + cands (delete (assoc tag cands) cands)) ; Tag read is no longer a candidate. + (while (not (string= "" tag)) + (if (member tag btags) ; User can enter it more than once, if not REQUIRE-MATCH. + (message "Tag `%s' already included" tag) + (push tag btags)) ; But we only add it once. + (setq tag (completing-read prompt2 cands nil require-match nil 'bmkp-tag-history) + cands (delete (assoc tag cands) cands))) + (nreverse btags))) + +;;;###autoload (autoload 'bmkp-list-all-tags "bookmark+") +(defun bmkp-list-all-tags (fullp current-only-p &optional msg-p) + ; Bound to `C-x x t l', (`T l' in bookmark list) + "List bookmark tags. +Show the list in the minibuffer or, if not enough space, in buffer +`*All Tags*'. The tags are listed alphabetically, respecting option +`case-fold-search'. + +With no prefix arg or with a plain prefix arg (`C-u'), the tags listed +are those defined by option `bmkp-tags-for-completion'. Otherwise +\(i.e., with a numeric prefix arg), the tags listed are those from the +current list of bookmarks only. + +With no prefix arg or with a negative prefix arg (e.g. `C--'), list +only the tag names. With a non-negative prefix arg (e.g. `C-1' or +plain `C-u'), list the full alist of tags. + +Note that when the full tags alist is shown, the same tag name appears +once for each of its different values. + +Non-interactively, non-nil MSG-P means display a status message." + (interactive (list (and current-prefix-arg (> (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (not (consp current-prefix-arg))) + 'MSG)) + (require 'pp) + (when msg-p (message "Gathering tags...")) + (pp-display-expression (sort (bmkp-tags-list (not fullp) current-only-p) + (if fullp + (lambda (t1 t2) (bmkp-string-less-case-fold-p (car t1) (car t2))) + 'bmkp-string-less-case-fold-p)) + "*All Tags*")) + +(defun bmkp-tags-list (&optional names-only-p current-only-p) + "List of all bookmark tags, per option `bmkp-tags-for-completion'. +Non-nil NAMES-ONLY-P means return a list of only the tag names. +Otherwise, return an alist of the full tags and set variable +`bmkp-tags-alist' to that alist, as a cache. + +Non-nil CURRENT-ONLY-P means ignore option `bmkp-tags-for-completion' +and return only the tags for the currently loaded bookmarks." + (let ((tags ()) + (opt-tags bmkp-tags-for-completion) + bmk-tags) + (when (or (eq opt-tags 'current) current-only-p) (setq opt-tags '(current))) + (dolist (entry opt-tags) + (typecase entry + (cons ; A bookmark file + (when (eq 'bmkfile (car entry)) + (setq entry (cdr entry) + tags (append tags (bmkp-tags-in-bookmark-file entry names-only-p))))) + (string (add-to-list 'tags (if names-only-p entry (list entry)))) + (symbol (when (eq entry 'current) + (bookmark-maybe-load-default-file) + (dolist (bmk bookmark-alist) + (setq bmk-tags (bmkp-get-tags bmk)) + (dolist (tag bmk-tags) + (add-to-list 'tags (if names-only-p (bmkp-tag-name tag) (bmkp-full-tag tag))))))))) + (unless names-only-p (setq bmkp-tags-alist tags)) + tags)) + +(defun bmkp-tags-in-bookmark-file (file &optional names-only-p) + "Return the list of tags from all bookmarks in bookmark-file FILE. +If FILE is a relative file name, it is expanded in `default-directory. +If FILE does not name a valid, bookmark file then nil is returned. +Non-nil NAMES-ONLY-P means return a list of only the tag names. +Otherwise, return an alist of the full tags." + (setq file (expand-file-name file)) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (let ((bookmark-save-flag nil) ; Just to play safe. + (bmk-alist ()) + (tags ()) + bmk-tags) + (if (not (file-readable-p file)) + (message "Cannot read bookmark file `%s'" file) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) + (condition-case nil ; Check whether it's a valid bookmark file. + (progn (bookmark-maybe-upgrade-file-format) + (unless (listp (setq bmk-alist (bookmark-alist-from-buffer))) (error ""))) + (error (message "Not a valid bookmark file: `%s'" file)))) + (dolist (bmk bmk-alist) + (setq bmk-tags (bmkp-get-tags bmk)) + (dolist (tag bmk-tags) + (add-to-list 'tags (if names-only-p (bmkp-tag-name tag) (bmkp-full-tag tag)))))) + tags)) + +(defun bmkp-tag-name (tag) + "Name of TAG. If TAG is an atom, then TAG, else (car TAG)." + (if (atom tag) tag (car tag))) + +(defun bmkp-full-tag (tag) + "Full cons entry for TAG. If TAG is a cons, then TAG, else (list TAG)." + (if (consp tag) tag (list tag))) + +;;;###autoload (autoload 'bmkp-remove-all-tags "bookmark+") +(defun bmkp-remove-all-tags (bookmark &optional no-update-p msg-p) + ; Bound to `C-x x t 0', (`T 0' in bookmark list) + "Remove all tags from BOOKMARK. +Non-interactively: + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + - Non-nil optional arg MSG-P means show a message about the removal." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) nil 'MSG)) + (when (and msg-p (null (bmkp-get-tags bookmark))) (error "Bookmark has no tags to remove")) + (let ((nb-removed (and (interactive-p) (length (bmkp-get-tags bookmark))))) + (bookmark-prop-set bookmark 'tags ()) + (unless no-update-p + (bmkp-tags-list) ; Update the tags cache. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list bookmark (not msg-p))) ; So remove `t' marker and add `*' marker. + (when (and msg-p nb-removed) (message "%d tags removed" nb-removed)))) ; Do after msg from refreshing. + + +;;;###autoload (autoload 'bmkp-add-tags "bookmark+") +(defun bmkp-add-tags (bookmark tags &optional no-update-p msg-p) + ; `C-x x t + b' (`b' for bookmark), (`T +' in bookmark list) + "Add TAGS to BOOKMARK. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. +Completion for the bookmark name is strict. +Completion for tags is lax: you are not limited to existing tags. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them. + +Non-interactively: + - TAGS is a list of strings. + - Non-nil MSG-P means display a message about the addition. + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + +The absolute value of the return value is the number of tags added. +If BOOKMARK was untagged before the operation, then the return value +is negative." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) + (bmkp-read-tags-completing nil nil current-prefix-arg) + nil + 'MSG)) + (let* ((newtags (copy-alist (bmkp-get-tags bookmark))) + (olen (length newtags))) + (dolist (tag tags) (unless (or (assoc tag newtags) (member tag newtags)) (push tag newtags))) + (bookmark-prop-set bookmark 'tags newtags) + (unless no-update-p + (bmkp-tags-list) ; Update the tags cache. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list bookmark (not msg-p))) ; So display `t' and `*' markers for BOOKMARK. + (let ((nb-added (- (length newtags) olen))) + (when msg-p (message "%d tags added. Now: %S" nb-added ; Echo just the tag names. + (let ((tgs (mapcar #'bmkp-tag-name newtags))) (setq tgs (sort tgs #'string<))))) + (when (and (zerop olen) (> (length newtags) 0)) (setq nb-added (- nb-added))) + nb-added))) + +;; $$$$$$ Not yet used +;;;###autoload (autoload 'bmkp-set-tag-value-for-navlist "bookmark+") +(defun bmkp-set-tag-value-for-navlist (tag value &optional msg-p) ; Bound to `C-x x t V' + "Set the value of TAG to VALUE, for each bookmark in the navlist. +If any of the bookmarks has no tag named TAG, then add one with VALUE." + (interactive (list (bmkp-read-tag-completing) (read (read-string "Value: ")) 'msg)) + (bmkp-set-tag-value-for-bookmarks bmkp-nav-alist tag value msg-p)) + +;; $$$$$$ Not yet used +(defun bmkp-set-tag-value-for-bookmarks (bookmarks tag value &optional msg-p) ; Not bound + "Set the value of TAG to VALUE, for each of the BOOKMARKS. +If any of the BOOKMARKS has no tag named TAG, then add one with VALUE." + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save only after `dolist'. + (dolist (bmk bookmarks) (bmkp-set-tag-value bmk tag value 'NO-UPDATE-P))) + (bmkp-tags-list) ; Update the tags cache. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list nil (not msg-p))) + +;;;###autoload (autoload 'bmkp-set-tag-value "bookmark+") +(defun bmkp-set-tag-value (bookmark tag value &optional no-update-p msg-p) ; Bound to `C-x x t v' + "For BOOKMARK's TAG, set the value to VALUE. +If BOOKMARK has no tag named TAG, then add one with value VALUE. +Non-interactively: + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + - Non-nil MSG-P means display a message about the updated value." + (interactive + (let* ((bmk (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name))) + (tag (bmkp-read-tag-completing "Tag: " (mapcar 'bmkp-full-tag (bmkp-get-tags bmk))))) + (list bmk tag (read (read-string "Value: ")) nil 'MSG))) + (unless (bmkp-has-tag-p bookmark tag) (bmkp-add-tags bookmark (list tag) 'NO-UPDATE-P)) ; No update yet. + (let* ((newtags (copy-alist (bmkp-get-tags bookmark))) + (assoc-tag (assoc tag newtags)) + (member-tag (and (not assoc-tag) (member tag newtags)))) + (if assoc-tag (setcdr assoc-tag value) (setcar member-tag (cons (car member-tag) value))) + (bookmark-prop-set bookmark 'tags newtags)) + (unless no-update-p + (bmkp-tags-list) ; Update the tags cache. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list bookmark (not msg-p))) ; So display `t' and `*' markers for BOOKMARK. + (when msg-p "Tag value set")) + +;;;###autoload (autoload 'bmkp-remove-tags "bookmark+") +(defun bmkp-remove-tags (bookmark tags &optional no-update-p msg-p) + ; `C-x x t - b' (`b' for bookmark), (`T -' in bookmark list) + "Remove TAGS from BOOKMARK. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them. + +Non-interactively: + - TAGS is a list of strings. The corresponding tags are removed. + - Non-nil MSG-P means display status messages. + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + +The absolute value of the return value is the number of tags removed. +If BOOKMARK is untagged after the operation, then the return value +is negative." + (interactive (let ((bmk (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)))) + (list bmk + (bmkp-read-tags-completing (mapcar 'bmkp-full-tag (bmkp-get-tags bmk)) + t current-prefix-arg) + nil + 'MSG))) + (let* ((remtags (copy-alist (bmkp-get-tags bookmark))) + (olen (length remtags))) + (if (null remtags) + (when msg-p (message "Bookmark has no tags to remove")) ; Do nothing if bookmark has no tags. + (setq remtags (bmkp-remove-if (lexical-let ((tgs tags)) + (lambda (tag) + (if (atom tag) (member tag tgs) (member (car tag) tgs)))) + remtags)) + (bookmark-prop-set bookmark 'tags remtags) + (unless no-update-p + (bmkp-tags-list) ; Update the tags cache. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list bookmark (not msg-p))) ; So remove `t' marker if no tags. + (let ((nb-removed (- olen (length remtags)))) + (when msg-p (message "%d tags removed. Now: %S" nb-removed ; Echo just the tag names. + (let ((tgs (mapcar #'bmkp-tag-name remtags))) + (setq tgs (sort tgs #'string<))))) + (when (and (zerop (length remtags)) (> olen 0)) (setq nb-removed (- nb-removed))) + nb-removed)))) + +;;;###autoload (autoload 'bmkp-remove-tags-from-all "bookmark+") +(defun bmkp-remove-tags-from-all (tags &optional msg-p) ; Bound to `C-x x t d', (`T d' in bookmark list) + "Remove TAGS from all bookmarks. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter each tag. +This affects all bookmarks, even those not showing in bookmark list. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them. + +Non-interactively: +* TAGS is a list of strings. The corresponding tags are removed. +* Non-nil optional arg MSG-P means show a message about the deletion." + (interactive + (if (not (y-or-n-p "Delete the tags you specify from ALL bookmarks? ")) + (error "OK - deletion canceled") + (list (bmkp-read-tags-completing nil t current-prefix-arg) 'MSG))) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save only after `dolist'. + (dolist (bmk (bookmark-all-names)) (bmkp-remove-tags bmk tags 'NO-UPDATE-P))) + (bmkp-tags-list) ; Update the tags cache (only once, at end). + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list nil (not msg-p)) ; So remove `t' markers when no tags anymore. + (when msg-p (message "Tags removed from all bookmarks: %S" tags))) + +;;;###autoload (autoload 'bmkp-rename-tag "bookmark+") +(defun bmkp-rename-tag (tag newname &optional msg-p) ; Bound to `C-x x t r', (`T r' in bookmark list) + "Rename TAG to NEWNAME in all bookmarks, even those not showing. +Non-interactively, non-nil MSG-P means display a message about the +deletion." + (interactive (list (bmkp-read-tag-completing "Tag (old name): ") + (bmkp-read-tag-completing "New name: ") + 'MSG)) + (let ((tag-exists-p nil) + (bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save only after `dolist'. + (dolist (bmk (bookmark-all-names)) + (let ((newtags (copy-alist (bmkp-get-tags bmk)))) + (when newtags + (let* ((assoc-tag (assoc tag newtags)) + (member-tag (and (not assoc-tag) (member tag newtags)))) + (cond (assoc-tag (setcar assoc-tag newname)) + (member-tag (setcar member-tag newname))) + (when (or assoc-tag member-tag) + (setq tag-exists-p t) + (bookmark-prop-set bmk 'tags newtags)))))) + (unless tag-exists-p (error "No such tag: `%s'" tag))) + (bmkp-tags-list) ; Update the tags cache now, after iterating. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + ;; (bmkp-refresh/rebuild-menu-list nil (not msg-p)) ; $$$$$$ No need to redisplay + (when msg-p (message "Renamed"))) + +;;;###autoload (autoload 'bmkp-copy-tags "bookmark+") +(defun bmkp-copy-tags (bookmark &optional msg-p) ; Bound to `C-x x t c', `C-x x t M-w' + "Copy tags from BOOKMARK, so you can paste them to another bookmark. +Note that you can copy from a BOOKMARK that has no tags or has an +empty tags list. In that case, the copied-tags list is empty, so if +you paste it as a replacement then the recipient bookmark will end up +with no tags. + +Non-interactively, non-nil MSG-P means display a message about the +number of tags copied." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) 'MSG)) + (let ((btags (bmkp-get-tags bookmark))) + (setq bmkp-copied-tags (copy-alist btags)) + (when msg-p (message "%d tags now available for pasting" (length btags))))) + +;;;###autoload (autoload 'bmkp-paste-add-tags "bookmark+") +(defun bmkp-paste-add-tags (bookmark &optional no-update-p msg-p) ; Bound to `C-x x t p', `C-x x t C-y' + "Add tags to BOOKMARK that were previously copied from another bookmark. +Return the number of tags added. +The tags are copied from `bmkp-copied-tags'. +Non-interactively: + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + - Non-nil MSG-P means display a message about the addition." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) nil 'MSG)) + (unless (listp bmkp-copied-tags) (error "`bmkp-paste-add-tags': `bmkp-copied-tags' is not a list")) + (bmkp-add-tags bookmark bmkp-copied-tags no-update-p msg-p)) + +;;;###autoload (autoload 'bmkp-paste-replace-tags "bookmark+") +(defun bmkp-paste-replace-tags (bookmark &optional no-update-p msg-p) ; Bound to `C-x x t q' + "Replace tags for BOOKMARK with those copied from another bookmark. +Return the number of tags for BOOKMARK. +The tags are copied from `bmkp-copied-tags'. +Any previously existing tags for BOOKMARK are *lost*. + +NOTE: It is by design that you can *remove all* tags from a bookmark +by copying an empty set of tags and then pasting to that bookmark +using this command. So be careful using it. If you want to be sure +that you do not replace tags with an empty list of tags, you can check +the value of variable `bmkp-copied-tags' before pasting. + +Non-interactively: + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + - Non-nil MSG-P means display a message about the addition." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) nil 'MSG)) + (unless (listp bmkp-copied-tags) + (error "`bmkp-paste-replace-tags': `bmkp-copied-tags' is not a list")) + (let ((has-tags-p (bmkp-get-tags bookmark))) + (when (and msg-p has-tags-p + (not (y-or-n-p "Existing tags will be LOST - really replace them? "))) + (error "OK - paste-replace tags canceled")) + (when has-tags-p (bmkp-remove-all-tags bookmark no-update-p msg-p) (sleep-for 0.5))) + (bmkp-add-tags bookmark bmkp-copied-tags no-update-p msg-p)) + + +;;(@* "Bookmark Predicates") +;; *** Bookmark Predicates *** + +(defun bmkp-annotated-bookmark-p (bookmark) + "Return non-nil if BOOKMARK has an annotation. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (let ((annotation (bookmark-get-annotation bookmark))) + (and annotation (not (string-equal annotation ""))))) + +(defun bmkp-autofile-bookmark-p (bookmark &optional prefix) + "Return non-nil if BOOKMARK is an autofile bookmark. +That means both: + * It is `bmkp-file-bookmark-p'. + * Its bookmark name is the same as the nondirectory part of its file + name (or of its `directory-file-name', if a directory). + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'. + +Non-interactively, non-nil optional arg PREFIX means that the bookmark +name is actually expected to be the file name prefixed by PREFIX (a +string)." + (setq bookmark (bmkp-get-bookmark bookmark)) + (and (bmkp-file-bookmark-p bookmark) + (let* ((file (bookmark-get-filename bookmark)) + (fname (file-name-nondirectory (if (file-directory-p file) + (directory-file-name file) + file)))) + (string= (if prefix (concat prefix fname) fname) (bmkp-bookmark-name-from-record bookmark))))) + +(defun bmkp-bookmark-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a bookmark-file bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-bookmark-file)) + +(defun bmkp-bookmark-list-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a bookmark-list bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-bookmark-list)) + +(defun bmkp-desktop-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a desktop bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-desktop)) + +;; Note: To avoid remote access, if bookmark does not have the Dired handler, then we insist +;; that it be for a local directory. IOW, we do not include remote directories that were not +;; bookmarked by Bookmark+ (and so do not have the Dired handler). +(defun bmkp-dired-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a Dired bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (or (eq (bookmark-get-handler bookmark) 'bmkp-jump-dired) + (bmkp-local-directory-bookmark-p bookmark))) + +(defun bmkp-dired-this-dir-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a Dired bookmark for the `default-directory'. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (and (bmkp-dired-bookmark-p bookmark) + (let ((dir (file-name-directory (bookmark-get-filename bookmark)))) + (bmkp-same-file-p dir default-directory)))) + +(defun bmkp-dired-wildcards-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a Dired buffer with wildcards. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (and (bmkp-dired-bookmark-p bookmark) + (let ((file (bookmark-get-filename bookmark))) + (and (stringp file) (bmkp-string-match-p (regexp-quote "*") file))))) + +(when (> emacs-major-version 24) ; Emacs 25+ + + (defun bmkp-eww-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an EWW bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-eww)) + + ) + +(defun bmkp-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a file or directory. +This excludes bookmarks of a more specific kind (e.g. Info, Gnus). +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let* ((filename (bookmark-get-filename bookmark)) + (nonfile-p (equal filename bmkp-non-file-filename)) + (handler (bookmark-get-handler bookmark))) + (and filename (not nonfile-p) + (or (not handler) + (memq handler bmkp-file-bookmark-handlers) + (equal handler (bmkp-default-handler-for-file filename))) + (not (bookmark-prop-get bookmark 'info-node))))) ; Emacs 20-21 Info: no handler. + +(defun bmkp-file-this-dir-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks file/subdir in `default-directory'. +This excludes bookmarks of a more specific kind (e.g. Info, Gnus). +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (and bookmark + (bmkp-file-bookmark-p bookmark) + (bmkp-same-file-p (file-name-directory (bookmark-get-filename bookmark)) default-directory))) + +(defun bmkp-flagged-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is flagged for deletion in `*Bookmark List*'. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (memq bookmark bmkp-flagged-bookmarks)) + +(defun bmkp-function-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a function bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-function)) + +(defun bmkp-gnus-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a Gnus bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (memq (bookmark-get-handler bookmark) + '(gnus-summary-bookmark-jump bmkp-jump-gnus bmkext-jump-gnus))) + +(defun bmkp-icicles-search-hits-bookmark-p (bookmark) + "Return non-nil if BOOKMARK records a list of Icicles search hits. +BOOKMARK is a bookmark name or a bookmark record. + +An Icicles search-hits bookmark is shown in the bookmark-list display +with face `bmkp-no-jump', because you cannot jump to it from there." + (setq bookmark (bmkp-get-bookmark bookmark)) + (eq (bookmark-get-handler bookmark) 'bmkp-jump-icicle-search-hits)) + +(defun bmkp-image-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an image-file bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (or (eq (bookmark-get-handler bookmark) 'image-bookmark-jump) + (and (fboundp 'image-file-name-regexp) ; In `image-file.el' (Emacs 22+). + (bmkp-file-bookmark-p bookmark) + (not (bmkp-dired-bookmark-p bookmark)) + (bmkp-string-match-p (image-file-name-regexp) (bookmark-get-filename bookmark))))) + +(defun bmkp-info-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an Info bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (or (eq (bookmark-get-handler bookmark) 'Info-bookmark-jump) + (and (not (bookmark-get-handler bookmark)) + (or (string= "*info*" (bmkp-get-buffer-name bookmark)) + (bookmark-prop-get bookmark 'info-node))))) ; Emacs 20-21 - no `buffer-name' entry. + +(defun bmkp-kmacro-list-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a kmacro-list bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-kmacro-list)) + +(defun bmkp-local-directory-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a local directory. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((file (bookmark-get-filename bookmark))) + (and (bmkp-local-file-bookmark-p bookmark) (file-directory-p file)))) + +(defun bmkp-local-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a local file or directory. +This excludes bookmarks of a more specific kind (e.g. Info, Gnus). +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (and (bmkp-file-bookmark-p bookmark) (not (bmkp-remote-file-bookmark-p bookmark)))) + +(defun bmkp-local-non-dir-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a local nondirectory file. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((file (bookmark-get-filename bookmark))) + (and (bmkp-local-file-bookmark-p bookmark) (not (file-directory-p file))))) + +(defun bmkp-buffer-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a non-file buffer. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (and (bmkp-get-buffer-name bookmark) + (let ((filep (bookmark-get-filename bookmark))) + (or (not filep) (equal filep bmkp-non-file-filename))))) + +(defun bmkp-man-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a `man' page bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (memq (bookmark-get-handler bookmark) '(bmkp-jump-man bmkp-jump-woman + bmkext-jump-man bmkext-jump-woman))) + +(defun bmkp-marked-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a marked bookmark in `*Bookmark List*'. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (unless (stringp bookmark) (setq bookmark (bmkp-bookmark-name-from-record bookmark))) + (bmkp-bookmark-name-member bookmark bmkp-bmenu-marked-bookmarks)) + +(defun bmkp-modified-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a modified bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (memq bookmark bmkp-modified-bookmarks)) + +(defun bmkp-navlist-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is in the current navigation list. +BOOKMARK is a bookmark name or a bookmark record." + (setq bookmark (bmkp-get-bookmark bookmark)) + (memq bookmark bmkp-nav-alist)) + +(defun bmkp-non-dir-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a nondirectory file. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((file (bookmark-get-filename bookmark))) + (and (bmkp-file-bookmark-p bookmark) (not (file-directory-p file))))) + +(defun bmkp-non-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a non-file bookmark (e.g *scratch*). +This excludes bookmarks of a more specific kind (e.g. Info, Gnus). +It includes bookmarks to existing buffers, as well as bookmarks +defined for buffers that do not currently exist. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let* ((filename (bookmark-get-filename bookmark)) + (nonfile-p (equal filename bmkp-non-file-filename))) + (and (bmkp-get-buffer-name bookmark) + (or (not filename) nonfile-p + ;; Ensure not remote before calling `file-exists-p'. (Do not prompt for password.) + (and (not (bmkp-file-remote-p filename)) (not (file-exists-p filename)))) + (not (bookmark-get-handler bookmark))))) + +(defun bmkp-non-invokable-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a non-invokable bookmark. +That is, jumping to it has no effect, because its handler is `ignore'. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'. + +A non-invokable bookmark is shown in the bookmark-list display with +face `bmkp-no-jump', because you cannot jump to it." + (eq (bookmark-get-handler bookmark) 'ignore)) + +(defun bmkp-orphaned-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an orphaned file or directory bookmark. +This means that the file recorded for BOOKMARK does not exist or is +not readable. But a Dired bookmark with wildcards in the file name is +assumed to be readable. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (and (bmkp-file-bookmark-p bookmark) + (if (bmkp-dired-bookmark-p bookmark) + (and (not (bmkp-dired-wildcards-bookmark-p bookmark)) + (not (file-readable-p (bookmark-get-filename bookmark)))) + (not (file-readable-p (bookmark-get-filename bookmark)))))) + +(defun bmkp-orphaned-local-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an orphaned local-file bookmark. +This means that the file name recorded for BOOKMARK is not remote, and +the file does not exist or is not readable. But a Dired bookmark with +wildcards in the file name is assumed to be readable. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (and (bmkp-local-file-bookmark-p bookmark) + (if (bmkp-dired-bookmark-p bookmark) + (and (not (bmkp-dired-wildcards-bookmark-p bookmark)) + (not (file-readable-p (bookmark-get-filename bookmark)))) + (not (file-readable-p (bookmark-get-filename bookmark)))))) + +(defun bmkp-orphaned-remote-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is an orphaned remote-file bookmark. +This means that the file name recorded for BOOKMARK is remote, and the +file does not exist or is not readable. But a Dired bookmark with +wildcards in the file name is assumed to be readable. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (and (bmkp-remote-file-bookmark-p bookmark) + (if (bmkp-dired-bookmark-p bookmark) + (and (not (bmkp-dired-wildcards-bookmark-p bookmark)) + (not (file-readable-p (bookmark-get-filename bookmark)))) + (not (file-readable-p (bookmark-get-filename bookmark)))))) + +(defun bmkp-region-bookmark-p (bookmark) + "Return non-nil if BOOKMARK has region information. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (and (bmkp-get-end-position bookmark) + (bookmark-get-position bookmark) + (/= (bookmark-get-position bookmark) (bmkp-get-end-position bookmark)))) + +(defun bmkp-remote-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a remote file or directory. +This includes remote Dired bookmarks, but otherwise excludes bookmarks +with handlers (e.g. Info, Gnus). + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let* ((handler (bookmark-get-handler bookmark)) + (file (bookmark-get-filename bookmark)) + (rem-file (and file (bmkp-file-remote-p file)))) + (and rem-file (or (not handler) (eq handler 'bmkp-jump-dired))))) + +(defun bmkp-remote-non-dir-file-bookmark-p (bookmark) + "Return non-nil if BOOKMARK bookmarks a remote nondirectory file. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((file (bookmark-get-filename bookmark))) + (and (bmkp-remote-file-bookmark-p bookmark) (not (file-directory-p file))))) + +(defun bmkp-snippet-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a snippet bookmark. +This means that it records a snippet of text and that jumping to it +copies that text to the `kill-ring'. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (eq (bookmark-get-handler bookmark) 'bmkp-jump-snippet)) + +(defun bmkp-temporary-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is temporary. +This means that it has a non-nil `bmkp-temp' entry. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (and bookmark (bookmark-prop-get bookmark 'bmkp-temp))) + +(defun bmkp-this-buffer-p (bookmark) + "Return non-nil if BOOKMARK's buffer is the current buffer. +But return nil if BOOKMARK has an associated file, but it is not the + buffer's file. +And return nil for bookmarks, such as desktops, that are not really + associated with a buffer, even if they have a `buffer-name' entry. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (and (let ((this-file (condition-case nil (bookmark-buffer-file-name) (error nil))) + (bmk-file (and (bmkp-file-bookmark-p bookmark) (bookmark-get-filename bookmark)))) + ;; Two possibilities: + ;; * Neither buffer nor bookmark has a file, and the buffer names are the same. + ;; * Both have files, and they are the same file. + (or (and (not this-file) (not bmk-file) (equal (bmkp-get-buffer-name bookmark) (buffer-name))) + (and this-file bmk-file (bmkp-same-file-p this-file bmk-file)))) + ;; If the buffer to check is from EWW, the buffer URL must match the bookmark URL. + (or (not (eq major-mode 'eww-mode)) + (and (fboundp 'bmkp-eww-url) (equal (bookmark-location bookmark) (bmkp-eww-url)))) ; Emacs 25+ + (not (bmkp-desktop-bookmark-p bookmark)) + (not (bmkp-bookmark-file-bookmark-p bookmark)) + (not (bmkp-sequence-bookmark-p bookmark)) + (not (bmkp-function-bookmark-p bookmark)) + (not (bmkp-variable-list-bookmark-p bookmark)))) + +(defun bmkp-this-file-p (bookmark) + "Return non-nil if BOOKMARK's file is the visited file. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((bmk-file (and (bmkp-file-bookmark-p bookmark) (bookmark-get-filename bookmark))) + (this-file (or (and (buffer-file-name) (bookmark-buffer-file-name)) + (and (eq major-mode 'dired-mode) (if (consp dired-directory) + (car dired-directory) + dired-directory))))) + (and bmk-file this-file (bmkp-same-file-p this-file bmk-file)))) + +(defun bmkp-last-specific-buffer-p (bookmark) + "Return t if BOOKMARK's `buffer-name' is `bmkp-last-specific-buffer'. +But return nil for bookmarks, such as desktops, that are not really +associated with a buffer, even if they have a `buffer-name' entry. +It does not matter whether the buffer exists. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((buf (bmkp-get-buffer-name bookmark))) + (and buf (string= buf bmkp-last-specific-buffer) + (not (bmkp-desktop-bookmark-p bookmark)) + (not (bmkp-bookmark-file-bookmark-p bookmark)) + (not (bmkp-sequence-bookmark-p bookmark)) + (not (bmkp-function-bookmark-p bookmark)) + (not (bmkp-variable-list-bookmark-p bookmark))))) + +(defun bmkp-last-specific-file-p (bookmark) + "Return t if BOOKMARK's `filename' is `bmkp-last-specific-file'. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (let ((file (bookmark-get-filename bookmark))) + (and file (bmkp-same-file-p file bmkp-last-specific-file)))) + +(defun bmkp-sequence-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a sequence bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-sequence)) + +(defun bmkp-some-marked-p (alist) + "Return non-nil if ALIST is nonempty and includes a marked bookmark." + (catch 'break (dolist (i alist) (and (bmkp-marked-bookmark-p i) (throw 'break t))))) + +(defun bmkp-some-unmarked-p (alist) + "Return non-nil if ALIST is nonempty and includes an unmarked bookmark." + (catch 'break (dolist (i alist) (and (not (bmkp-marked-bookmark-p i)) (throw 'break t))))) + +(defun bmkp-url-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a URL bookmark. +This means that it satifies `bmkp-eww-bookmark-p' (Emacs 25+), +`bmkp-w3m-bookmark-p', or `bmkp-url-browse-bookmark-p'. + +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (or (and (fboundp 'bmkp-eww-bookmark-p) (bmkp-eww-bookmark-p bookmark)) + (bmkp-w3m-bookmark-p bookmark) + (bmkp-url-browse-bookmark-p bookmark))) + +(defun bmkp-url-browse-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a `browse-url' bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-url-browse)) + +(defun bmkp-variable-list-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a variable-list bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (eq (bookmark-get-handler bookmark) 'bmkp-jump-variable-list)) + +(defun bmkp-w3m-bookmark-p (bookmark) + "Return non-nil if BOOKMARK is a W3M bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (memq (bookmark-get-handler bookmark) '(bmkp-jump-w3m bmkext-jump-w3m))) + + + + + +;;(@* "General Utility Functions") +;; *** General Utility Functions *** + +(when (and (fboundp 'cl-puthash) (not (fboundp 'puthash))) ; Emacs 20 with `cl-extra.el' loaded. + (defalias 'puthash 'cl-puthash)) + +(if (fboundp 'puthash) ; Emacs 21+, or Emacs 20 with `cl-extra.el' loaded. + (defun bmkp-remove-dups (sequence &optional test) + "Copy of SEQUENCE with duplicate elements removed. +Optional arg TEST is the test function. If nil, test with `equal'. +See `make-hash-table' for possible values of TEST." + (setq test (or test #'equal)) + (let ((htable (make-hash-table :test test))) + (loop for elt in sequence + unless (gethash elt htable) + do (puthash elt elt htable) + finally return (loop for i being the hash-values in htable collect i)))) + + (defun bmkp-remove-dups (list &optional use-eq) + "Copy of LIST with duplicate elements removed. +Test using `equal' by default, or `eq' if optional USE-EQ is non-nil." + (let ((tail list) + new) + (while tail + (unless (if use-eq (memq (car tail) new) (member (car tail) new)) + (push (car tail) new)) + (pop tail)) + (nreverse new)))) + +(defun bmkp-unpropertized-string (string) + "Return a copy of STRING, but with properties removed. +Does not change the original STRING." + (let ((strg (copy-sequence string))) + (set-text-properties 0 (length strg) () strg) + strg)) + +;; For a name propertized with `bmkp-full-record', this is similar to `bmkp-assoc-delete-all'. +(defun bmkp-delete-bookmark-name-from-list (delname bnames) + "Delete names that represent the same bookmark as DELNAME from BNAMES. +This means that they are `string=' and they either have no property +`bmkp-full-record' or that property has the same value. +Return the modified list BNAMES." + ;; $$$$$$ Can we change `equal' to `eq' everywhere here? + (let ((delprop (get-text-property 0 'bmkp-full-record delname)) + bmkprop) + (if (not delprop) + (setq bnames (delete delname bnames)) ; Unpropertized - just use `delete'. + ;; Propertized. Delete names that are `string=' and have the same property value or none. + (while (and bnames (string= delname (car bnames)) ; Delete those at list beginning. + (or (not (setq bmkprop (get-text-property 0 'bmkp-full-record (car bnames)))) + (equal delprop bmkprop))) + (setq bnames (cdr bnames))) + (let ((tail bnames) ; Delete those not at list beginning. + tail-cdr) + (while (setq tail-cdr (cdr tail)) + (if (and (car tail-cdr) + (string= delname (car tail-cdr)) + (or (not (setq bmkprop (get-text-property 0 'bmkp-full-record (car tail-cdr)))) + (equal delprop bmkprop))) + (setcdr tail (cdr tail-cdr)) + (setq tail tail-cdr)))) + bnames))) + +(defun bmkp-bookmark-name-member (name names) + "Like `member', but tests also bookmark NAME's `bmkp-full-record' property. +Return the tail of NAMES whose car is NAME with the property match. +If NAME has no `bmkp-full-record' property then this is just `member'. +If NAME has property `bmkp-full-record', then test whether both: + a. NAME is a member of NAMES and + b. NAME has the same `bmkp-full-record' value as an element of NAMES." + ;; $$$$$$ Can we change `equal' to `eq' here? + (let ((prop (get-text-property 0 'bmkp-full-record name))) + (if (or (null name) (not prop)) + (member name names) ; Unpropertized - just use `member'. + (while (and names (not (and (stringp (car names)) + (string= name (car names)) ; = `bmkp-names-same-bookmark-p'. + ;; If unpropertized in NAMES, then assume it's the one. + (or (not (get-text-property 0 'bmkp-full-record (car names))) + (equal prop (get-text-property 0 'bmkp-full-record (car names))))))) + (setq names (cdr names))) + names))) + +(defun bmkp-names-same-bookmark-p (name1 name2) + "Return non-nil if the two strings name the same bookmark. +The strings are `string=' and their `bmkp-full-record' property values +for the first character are `equal'." + + ;; $$$$$$ Can we change `equal' to `eq' here? + (and (string= name1 name2) + (equal (get-text-property 0 'bmkp-full-record name1) + (get-text-property 0 'bmkp-full-record name2)))) + +(defun bmkp-read-buffers () +"Read names of buffers associated with bookmarks. +Invoke `bmkp-completing-read-buffer-name' repeatedly till input is empty." + (let ((buffs ()) + buff) + (while (and (setq buff (bmkp-completing-read-buffer-name 'ALLOW-EMPTY)) (not (string= "" buff))) + (add-to-list 'buffs buff)) + buffs)) + +(defun bmkp-read-files () + "Read names of files associated with bookmarks. +Invoke `bmkp-completing-read-file-name' repeatedly till input is empty." + (let ((use-file-dialog nil) + (files ()) + file) + (while (and (setq file (bmkp-completing-read-file-name 'ALLOW-EMPTY)) (not (string= "" file))) + (add-to-list 'files file)) + files)) + +(defun bmkp-remove-if (pred xs) + "A copy of list XS with no elements that satisfy predicate PRED." + (let ((result ())) + (dolist (x xs) (unless (funcall pred x) (push x result))) + (nreverse result))) + +(defun bmkp-remove-if-not (pred xs) + "A copy of list XS with only elements that satisfy predicate PRED." + (let ((result ())) + (dolist (x xs) (when (funcall pred x) (push x result))) + (nreverse result))) + +;; Similar to `every' in `cl-extra.el', without non-list sequences and multiple sequences. +(defun bmkp-every (predicate list) + "Return t if PREDICATE is true for all elements of LIST; else nil." + (while (and list (funcall predicate (car list))) (setq list (cdr list))) + (null list)) + +;; Same as `zz-some' in `zones.el'. +;; This is NOT the same as `some' in `cl-extra.el', even without non-list sequences and multiple sequences. +;; +;; If PREDICATE is satisfied by a list element ELEMENT, so that it returns a non-nil value VALUE for ELEMENT, +;; then this returns the cons (ELEMENT . VALUE). It does not return just VALUE. +(defun bmkp-some (predicate list) + "Return non-nil if PREDICATE applied to some element of LIST is true. +The value returned is a cons, (ELEMENT . VALUE), where ELEMENT is the +first list element that satisfies PREDICATE and VALUE is the value of +PREDICATE applied to ELEMENT." + (let (elt val) + (catch 'bmkp-some + (while list + (when (setq val (funcall predicate (setq elt (pop list)))) + (throw 'bmkp-some (cons elt val)))) + nil))) + +;; From `cl-seq.el', function `union', without keyword treatment. +;; (Same as `icicle-set-union' in `icicles-fn.el'.) +(defun bmkp-set-union (list1 list2) + "Combine LIST1 and LIST2 using a set-union operation. +The result list contains all items that appear in either LIST1 or +LIST2. Comparison is done using `equal'. This is a non-destructive +function; it copies the data if necessary." + (cond ((null list1) list2) + ((null list2) list1) + ((equal list1 list2) list1) + (t + (unless (>= (length list1) (length list2)) + (setq list1 (prog1 list2 (setq list2 list1)))) ; Swap them. + (while list2 + (unless (member (car list2) list1) (setq list1 (cons (car list2) list1))) + (setq list2 (cdr list2))) + list1))) + +(defun bmkp-upcase (string) + "`upcase', but in case of error, return original STRING. +This works around an Emacs 20 problem that occurs if STRING contains +binary data (weird chars)." + (condition-case nil (upcase string) (error string))) + +;; Thx to Michael Heerdegen and Michael Albinus for help with this one. +(defun bmkp-same-file-p (file1 file2) + "Return non-nil if FILE1 and FILE2 name the same file. +If either name is not absolute, then it is expanded relative to +`default-directory' for the test." + (let* ((remote1 (bmkp-file-remote-p file1)) + (remote2 (bmkp-file-remote-p file2)) + (ignore-case-p (and (not remote1) (not remote2) ; Assume case-sensitive if remote. + (if (boundp 'read-file-name-completion-ignore-case) + (eval (car (get 'read-file-name-completion-ignore-case + 'standard-value))) + ;; From the Emacs 24 definition of `read-file-name-completion-ignore-case'. + (memq system-type '(ms-dos windows-nt darwin cygwin)))))) + (and (equal remote1 remote2) + (if (fboundp 'file-equal-p) + (file-equal-p file1 file2) + (let ((ft1 (file-truename (expand-file-name file1))) + (ft2 (file-truename (expand-file-name file2)))) + (eq t (compare-strings ft1 0 (length ft1) ft2 0 (length ft2) ignore-case-p))))))) + +;;; $$$$$$ +;;; (defun bmkp-same-file-p (file1 file2) +;;; "Return non-nil if FILE1 and FILE2 name the same file. +;;; If either name is not absolute, then it is expanded relative to +;;; `default-directory' for the test." +;;; (and (equal (bmkp-file-remote-p file1) (bmkp-file-remote-p file2)) +;;; (string= (file-truename (expand-file-name file1)) +;;; (file-truename (expand-file-name file2))))) + +;;; $$$$$$ +;;; (defun bmkp-file-remote-p (file-name) +;;; "Returns non-nil if string FILE-NAME is likely to name a remote file." +;;; (if (fboundp 'file-remote-p) +;;; (file-remote-p file-name) +;;; (and (fboundp 'ffap-file-remote-p) (ffap-file-remote-p file-name)))) + +(defun bmkp-file-remote-p (file) + "Test whether FILE specifies a location on a remote system. +Return nil or a string identifying the remote connection (ideally a +prefix of FILE). + +A file is considered remote if accessing it is likely to be slower or +less reliable than accessing local files. + +This is `file-remote-p', if that function is available. If not, use a +simple match against rough remote file syntax: `/...:'. + +Unless `file-remote-p' is available and FILE has a `file-remote-p' +handler that opens a remote connection, `bmkp-file-remote-p' does not +open a remote connection." + (if (fboundp 'file-remote-p) + (file-remote-p file) + (and (stringp file) (string-match "\\`/[^/]+:" file) (match-string 0 file)))) + +(defun bmkp-float-time (&optional specified-time) + "Same as `float-time'. (Needed for Emacs 20.)" + (if (fboundp 'float-time) + (float-time specified-time) + (unless specified-time (setq specified-time (current-time))) + (+ (* (float (nth 0 specified-time)) (expt 2 16)) (nth 1 specified-time)))) + +(defun bmkp-string-less-case-fold-p (s1 s2) + "Like `string-lessp', but respect `case-fold-search'." + (when case-fold-search (setq s1 (bmkp-upcase s1) + s2 (bmkp-upcase s2))) + (string-lessp s1 s2)) + +(defun bmkp-make-plain-predicate (pred &optional final-pred) + "Return a plain predicate that corresponds to component-predicate PRED. +PRED and FINAL-PRED correspond to their namesakes in +`bmkp-sort-comparer' (which see). + +PRED should return `(t)', `(nil)', or nil. + +Optional arg FINAL-PRED is the final predicate to use if PRED cannot +decide (returns nil). If FINAL-PRED is nil, then `bmkp-alpha-p', the +plain-predicate equivalent of `bmkp-alpha-cp' is used as the final +predicate." + `(lambda (b1 b2) (let ((res (funcall ',pred b1 b2))) + (if res (car res) (funcall ',(or final-pred 'bmkp-alpha-p) b1 b2))))) + +(defun bmkp-repeat-command (command) + "Repeat COMMAND." + (require 'repeat) ; Define its vars before we let-bind them. + (let ((repeat-previous-repeated-command command) + (repeat-message-function #'ignore) + (last-repeatable-command 'repeat)) + (repeat nil))) + + +;;; If you need this for some reason, uncomment it. +;;; (defun bmkp-fix-bookmark-alist-and-save () +;;; "Update format of `bookmark-default-file' created in summer of 2009. +;;; You DO NOT NEED THIS, unless you happen to have used `bookmark+.el' in +;;; the summer of 2009 to create non-file bookmarks. If you did that, +;;; then some of those bookmarks might cause vanilla Emacs (emacs -Q) to +;;; raise an error. You can use this command to fix that problem: it +;;; modifies your existing `bookmark-default-file' (`~/.emacs.bmk'), after +;;; backing up that file (suffixing the name with \"_saveNUMBER\")." +;;; (interactive) +;;; (require 'cl) ; For `gensym' +;;; (if (not (yes-or-no-p +;;; "This will modify your bookmark file, after backing it up. OK? ")) +;;; (message "OK, nothing done") +;;; (bookmark-maybe-load-default-file) +;;; (let ((bkup-file (concat bookmark-default-file "_" (symbol-name (gensym "save"))))) +;;; (when (condition-case err +;;; (progn +;;; (with-current-buffer (let ((enable-local-variables ())) +;;; (find-file-noselect bookmark-default-file)) +;;; (write-file bkup-file)) +;;; (dolist (bmk bookmark-alist) +;;; (let ((fn-tail (member '(filename) bmk)) +;;; (hdlr (bookmark-get-handler (car bmk)))) +;;; (cond (fn-tail +;;; (setcar fn-tail (cons 'filename bmkp-non-file-filename))) +;;; ((and (eq hdlr 'bmkp-jump-gnus) +;;; (not (assoc 'filename bmk))) +;;; (setcdr bmk (cons (cons 'filename bmkp-non-file-filename) +;;; (cdr bmk))))))) +;;; t) ; Be sure `dolist' exit with t to allow saving. +;;; (error (error "No changes made. %s" (error-message-string err)))) +;;; (bookmark-save) +;;; (message "Bookmarks file fixed. Old version is `%s'" bkup-file))))) + + +;;(@* "Bookmark Entry Access Functions") +;; *** Bookmark Entry Access Functions *** + +(defun bmkp-get-buffer-name (bookmark) + "Return the `buffer-name' entry for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (bookmark-prop-get bookmark 'buffer-name)) + +(defun bmkp-get-end-position (bookmark) + "Return the `end-position' entry for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (bookmark-prop-get bookmark 'end-position)) + +(defun bmkp-get-visits-count (bookmark) + "Return the `visits' count for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (bookmark-prop-get bookmark 'visits)) + +(defun bmkp-get-visit-time (bookmark) + "Return the `time' value for BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + ;; Should just be a prop-get, but when first implemented, we used a float + ;; instead of a time cons, so we need to convert any such obsolete recorded times. + (let ((vt (bookmark-prop-get bookmark 'time))) + (when (numberp vt) ; Convert mid-2009 time values (floats) to cons form. + (setq vt (if (boundp 'seconds-to-time) + (seconds-to-time vt) + (list (floor vt 65536) ; Inlined `seconds-to-time', for Emacs 20-21. + (floor (mod vt 65536)) + (floor (* (- vt (ffloor vt)) 1000000)))))) + vt)) + + +;;(@* "Sorting - General Functions") +;; *** Sorting - General Functions *** + +(defun bmkp-sort-omit (alist &optional omit) + "Sort a copy of ALIST, omitting any elements whose keys are in OMIT. +Return the copy. +Do not sort if `bmkp-sort-comparer' is nil. +This is a non-destructive operation: ALIST is not modified. + +Sorting is done using using `bmkp-sort-comparer'. +If `bmkp-reverse-sort-p' is non-nil, then reverse the sort order. +Keys are compared for sorting using `equal'. + +If optional arg OMIT is non-nil, then it is a list of keys. Omit from +the return value any elements with keys in the list." + (lexical-let ((new-alist (bmkp-remove-omitted alist omit)) + (sort-fn (and bmkp-sort-comparer (if (and (not (functionp bmkp-sort-comparer)) + (consp bmkp-sort-comparer)) + 'bmkp-multi-sort + bmkp-sort-comparer)))) + (when sort-fn + (setq new-alist (sort new-alist (if bmkp-reverse-sort-p + (lambda (a b) (not (funcall sort-fn a b))) + sort-fn)))) + new-alist)) + +(defun bmkp-remove-omitted (alist &optional omit) + "Copy of bookmark ALIST without bookmarks whose names are in list OMIT. +Name comparison is done using `bmkp-bookmark-name-member'. +If optional arg OMIT is non-nil, then omit from the return value any +elements with keys in list OMIT." + (let ((new ())) + (dolist (ii alist) (unless (bmkp-bookmark-name-member (car ii) omit) (push ii new))) + (nreverse new))) + +;;; $$$$$$ No longer used. +;;; (defun bmkp-sort-and-remove-dups (alist &optional omit) +;;; "Remove duplicates from a copy of ALIST, then sort it and return it. +;;; Do not sort if `bmkp-sort-comparer' is nil. +;;; Always remove duplicates. Keep only the first element with a given +;;; key. This is a non-destructive operation: ALIST is not modified. + +;;; Sorting is done using using `bmkp-sort-comparer'. +;;; If `bmkp-reverse-sort-p' is non-nil, then reverse the sort order. +;;; Keys are compared for sorting using `equal'. +;;; If optional arg OMIT is non-nil, then omit from the return value any +;;; elements with keys in list OMIT." +;;; (lexical-let ((new-alist (bmkp-remove-assoc-dups alist omit)) +;;; (sort-fn (and bmkp-sort-comparer (if (and (not (functionp bmkp-sort-comparer)) +;;; (consp bmkp-sort-comparer)) +;;; 'bmkp-multi-sort +;;; bmkp-sort-comparer)))) +;;; (when sort-fn +;;; (setq new-alist (sort new-alist (if bmkp-reverse-sort-p +;;; (lambda (a b) (not (funcall sort-fn a b))) +;;; sort-fn)))) +;;; new-alist)) + +;;; KEEP this simpler version also. This uses `run-hook-with-args-until-success', but it +;;; does not respect `bmkp-reverse-multi-sort-p'. +;;; (defun bmkp-multi-sort (b1 b2) +;;; "Try predicates in `bmkp-sort-comparer', in order, until one decides. +;;; See the description of `bmkp-sort-comparer'." +;;; (let* ((preds (append (car bmkp-sort-comparer) (cdr bmkp-sort-comparer))) +;;; (result (run-hook-with-args-until-success 'preds b1 b2))) +;;; (if (consp result) +;;; (car result) +;;; result))) + +;;; $$$$$$ No longer used. +;;; (defun bmkp-remove-assoc-dups (alist &optional omit) +;;; "Shallow copy of ALIST without elements that have duplicate keys. +;;; Only the first element of those with the same key is kept. +;;; Keys are compared using `equal'. +;;; If optional arg OMIT is non-nil, then omit from the return value any +;;; elements with keys in list OMIT." +;;; (let ((new ())) +;;; (dolist (ii alist) (unless (or (assoc (car ii) new) (member (car ii) omit)) (push ii new))) +;;; (nreverse new))) + + +;; This Lisp definition respects `bmkp-reverse-multi-sort-p', and can be extended. +(defun bmkp-multi-sort (b1 b2) + "Try predicates in `bmkp-sort-comparer', in order, until one decides. +See the description of `bmkp-sort-comparer'. +If `bmkp-reverse-multi-sort-p' is non-nil, then reverse the order for +using multi-sorting predicates." + (let ((preds (car bmkp-sort-comparer)) + (final-pred (cadr bmkp-sort-comparer)) + (result nil)) + (when bmkp-reverse-multi-sort-p (setq preds (reverse preds))) + (catch 'bmkp-multi-sort + (dolist (pred preds) + (setq result (funcall pred b1 b2)) + (when (consp result) + (when bmkp-reverse-multi-sort-p (setq result (list (not (car result))))) + (throw 'bmkp-multi-sort (car result)))) + (and final-pred (if bmkp-reverse-multi-sort-p + (not (funcall final-pred b1 b2)) + (funcall final-pred b1 b2)))))) + + +;; The description returned is only approximate. The effect of `bmkp-reverse-multi-sort-p' is not +;; always intuitive, but it can often be useful. What's not always intuitive is the placement +;; (the order) of bookmarks that are not sorted by the predicates. +;; +(defun bmkp-sorting-description (order) + "Return a string describing sort ORDER." + (concat + (if (and order bmkp-sort-comparer) + order + (concat (and order (format "(%s) " order)) "turned OFF")) + (cond ((not bmkp-sort-comparer) nil) + ((not (and (consp bmkp-sort-comparer) (consp (car bmkp-sort-comparer)))) ; Ordinary single pred. + (if bmkp-reverse-sort-p " (REVERSED)" "")) + ((not (cadr (car bmkp-sort-comparer))) ; Single predicate. + (if (or (and bmkp-reverse-sort-p (not bmkp-reverse-multi-sort-p)) + (and bmkp-reverse-multi-sort-p (not bmkp-reverse-sort-p))) + " (REVERSED)" + "") + ;; If we wanted to distinguish the two: + ;; (if (and bmkp-reverse-sort-p (not bmkp-reverse-multi-sort-p)) + ;; "; REVERSED" + ;; (if (and bmkp-reverse-multi-sort-p (not bmkp-reverse-sort-p)) + ;; "; REVERSED +" + ;; "")) + ) + ;; At least two predicates. + ((and bmkp-reverse-sort-p (not bmkp-reverse-multi-sort-p)) " (REVERSED)") + ((and bmkp-reverse-multi-sort-p (not bmkp-reverse-sort-p)) " (each pred group reversed)") + ((and bmkp-reverse-multi-sort-p bmkp-reverse-sort-p) " (order of pred groups reversed)") + (t "")))) + +(defun bmkp-msg-about-sort-order (order &optional prefix-msg suffix-msg) + "Display a message mentioning sort ORDER and direction. +Optional arg PREFIX-MSG is prepended to the constructed message, and +terminated with a period. +Similarly, SUFFIX-MSG is appended, after appending \". \"." + (let ((msg (concat "Sorting " (bmkp-sorting-description order)))) + (when prefix-msg (setq msg (concat prefix-msg ". " msg))) + (when suffix-msg (setq msg (concat msg ". " suffix-msg))) + (message msg))) + + +;;(@* "Sorting - Commands") +;; *** Sorting - Commands *** + +(defun bmkp-current-sort-order () + "Current sort order or sort function, as a string, or nil if none." + (car (rassoc bmkp-sort-comparer bmkp-sort-orders-alist))) + + +;;(@* "Sorting - General Predicates") +;; *** Sorting - General Predicates *** + +(defun bmkp-annotated-cp (b1 b2) + "True if bookmark B1 is annotated and bookmark B2 is not. +Return nil if incomparable as described. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((m1 (bmkp-annotated-bookmark-p b1)) + (m2 (bmkp-annotated-bookmark-p b2))) + (cond ((and m1 m2) nil) + (m1 '(t)) + (m2 '(nil)) + (t nil)))) + +(defun bmkp-flagged-cp (b1 b2) + "True if bookmark B1 is flagged for deletion and bookmark B2 is not. +Return nil if incomparable as described. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((m1 (bmkp-flagged-bookmark-p b1)) + (m2 (bmkp-flagged-bookmark-p b2))) + (cond ((and m1 m2) nil) + (m1 '(t)) + (m2 '(nil)) + (t nil)))) + +(defun bmkp-marked-cp (b1 b2) + "True if bookmark B1 is marked and bookmark B2 is not. +Return nil if incomparable as described. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((m1 (bmkp-marked-bookmark-p b1)) + (m2 (bmkp-marked-bookmark-p b2))) + (cond ((and m1 m2) nil) + (m1 '(t)) + (m2 '(nil)) + (t nil)))) + +(defun bmkp-modified-cp (b1 b2) + "True if bookmark B1 is modified and bookmark B2 is not. +Return nil if incomparable as described. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((m1 (bmkp-modified-bookmark-p b1)) + (m2 (bmkp-modified-bookmark-p b2))) + (cond ((and m1 m2) nil) + (m1 '(t)) + (m2 '(nil)) + (t nil)))) + +(defun bmkp-tagged-cp (b1 b2) + "True if bookmark B1 is tagged and bookmark B2 is not. +Return nil if incomparable as described. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((m1 (bmkp-tagged-bookmark-p b1)) + (m2 (bmkp-tagged-bookmark-p b2))) + (cond ((and m1 m2) nil) + (m1 '(t)) + (m2 '(nil)) + (t nil)))) + +(defun bmkp-visited-more-cp (b1 b2) + "True if bookmark B1 was visited more often than B2. +Return nil if incomparable as described. + +True also if B1 was visited but B2 was not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((v1 (bmkp-get-visits-count b1)) + (v2 (bmkp-get-visits-count b2))) + (cond ((and v1 v2) + (cond ((> v1 v2) '(t)) + ((> v2 v1) '(nil)) + (t nil))) + (v1 '(t)) + (v2 '(nil)) + (t nil)))) + +(defun bmkp-bookmark-creation-cp (b1 b2) + "True if bookmark B1 was created more recently than B2. +Return nil if incomparable as described. + +True also if B1 has a `created' entry but B2 has none. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((t1 (bookmark-prop-get b1 'created)) + (t2 (bookmark-prop-get b2 'created))) + (cond ((and t1 t2) + (setq t1 (bmkp-float-time t1) + t2 (bmkp-float-time t2)) + (cond ((> t1 t2) '(t)) + ((> t2 t1) '(nil)) + (t nil))) + (t1 '(t)) + (t2 '(nil)) + (t nil)))) + +;; Not used currently. +(defun bmkp-same-creation-time-p (b1 b2) + "Return non-nil if `B1 and B2 have same `created' entry. +If neither has a `created' entry (vanilla bookmarks), then return +non-nil if the full bookmarks are `equal'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (let ((time1 (bookmark-prop-get b1 'created)) + (time2 (bookmark-prop-get b2 'created))) + (if (or time1 time2) (equal time1 time2) (equal b1 b2)))) + +(defun bmkp-bookmark-last-access-cp (b1 b2) + "True if bookmark B1 was visited more recently than B2. +Return nil if incomparable as described. + +True also if B1 was visited but B2 was not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((t1 (bmkp-get-visit-time b1)) + (t2 (bmkp-get-visit-time b2))) + (cond ((and t1 t2) + (setq t1 (bmkp-float-time t1) + t2 (bmkp-float-time t2)) + (cond ((> t1 t2) '(t)) + ((> t2 t1) '(nil)) + (t nil))) + (t1 '(t)) + (t2 '(nil)) + (t nil)))) + +(defun bmkp-buffer-last-access-cp (b1 b2) + "True if bookmark B1's buffer or file was visited more recently than B2's. +Return nil if incomparable as described. + +A bookmark to an existing buffer sorts before a file bookmark, even if +the buffer has not been visited during this session. + +True also if B1 has a buffer but B2 does not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((buf1 (bmkp-get-buffer-name b1)) + (buf2 (bmkp-get-buffer-name b2)) + f1 f2 t1 t2) + (setq buf1 (and buf1 (get-buffer buf1)) + buf2 (and buf2 (get-buffer buf2))) + (cond ((and buf1 buf2) ; Both buffers exist. See whether they were accessed. + (when buf1 (setq buf1 (member buf1 (buffer-list)) + buf1 (length buf1))) + (when buf2 (setq buf2 (member buf2 (buffer-list)) + buf2 (length buf2))) + (cond ((and buf1 buf2) ; Both were accessed. Priority to most recent access. + (cond ((< buf1 buf2) '(t)) + ((< buf2 buf1) '(nil)) + (t nil))) + (buf1 '(t)) ; Only buf1 was accessed. + (buf2 '(nil)) ; Only buf2 was accessed. + (t nil))) ; Neither was accessed. + + (buf1 '(t)) ; Only buf1 exists. + (buf2 '(nil)) ; Only buf2 exists. + (t nil)))) ; Neither buffer exists + +;; EWW. Not used yet. +(when (> emacs-major-version 24) ; Emacs 25 + + (defun bmkp-eww-cp (b1 b2) + "True if bookmark B1 sorts as an EWW URL bookmark before B2. +Return nil if neither sorts before the other. + +Two EWW URL bookmarks are compared alphabetically, by their URLs. +True also if B1 is a EWW bookmark but B2 is not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((e1 (bmkp-eww-bookmark-p b1)) + (e2 (bmkp-eww-bookmark-p b2))) + (cond ((and e1 e2) + (setq e1 (bookmark-get-filename b1) + e2 (bookmark-get-filename b2)) + (cond ((string-lessp e1 e2) '(t)) + ((string-lessp e2 e1) '(nil)) + (t nil))) + (e1 '(t)) + (e2 '(nil)) + (t nil)))) + + ) + +(defun bmkp-handler-cp (b1 b2) + "True if bookmark B1's handler name sorts alphabetically before B2's. +Return nil if neither sorts before the other. + +Two bookmarks with handlers are compared alphabetically, by their +handler-function names, respecting `case-fold-search'. +True also if B1 has a handler but B2 has not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((h1 (bookmark-get-handler b1)) + (h2 (bookmark-get-handler b2))) + (cond ((and h1 h2 (symbolp h1) (symbolp h2)) + ;; Pretend woman bookmarks are man bookmarks, to keep them together. + (when (eq h1 'bmkp-jump-woman) (setq h1 'bmkp-jump-man)) + (when (eq h2 'bmkp-jump-woman) (setq h2 'bmkp-jump-man)) + (setq h1 (symbol-name h1) + h2 (symbol-name h2)) + (when case-fold-search (setq h1 (bmkp-upcase h1) + h2 (bmkp-upcase h2))) + (cond ((string-lessp h1 h2) '(t)) + ((string-lessp h2 h1) '(nil)) + (t nil))) + (h1 '(t)) + (h2 '(nil)) + (t nil)))) + +;; Keep the alias for a while, in case someone has it referenced in a state file. +(defalias 'bmkp-info-cp 'bmkp-info-node-name-cp) +(bmkp-make-obsolete 'bmkp-info-cp 'bmkp-info-node-name-cp "2017-07-03") + +(defun bmkp-info-node-name-cp (b1 b2) + "True if bookmark B1 sorts as an Info bookmark before B2. +Return nil if neither sorts before the other. + +Two Info bookmarks are compared first by manual name, then by node +name, then by position. + +If `bmkp-info-sort-ignores-directories-flag' is non-nil then manual +names are used. If it is nil then absolute file names for the manuals +are used. + +True also if B1 is an Info bookmark but B2 is not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((i1 (bmkp-info-bookmark-p b1)) + (i2 (bmkp-info-bookmark-p b2)) + (fn (if bmkp-info-sort-ignores-directories-flag #'file-name-nondirectory #'abbreviate-file-name))) + (cond ((and i1 i2) + (setq i1 (funcall fn (bookmark-get-filename b1)) + i2 (funcall fn (bookmark-get-filename b2))) + (when case-fold-search (setq i1 (bmkp-upcase i1) + i2 (bmkp-upcase i2))) + (cond ((string-lessp i1 i2) '(t)) ; Compare manuals (file names). + ((string-lessp i2 i1) '(nil)) + (t ; Compare node names. + (setq i1 (bookmark-prop-get b1 'info-node) + i2 (bookmark-prop-get b2 'info-node)) + (cond ((string-lessp i1 i2) '(t)) + ((string-lessp i2 i1) '(nil)) + (t + (setq i1 (bookmark-get-position b1) + i2 (bookmark-get-position b2)) + (cond ((or (not i1) (not i2)) '(t)) ; Fallback if no `position' entry. + ((<= i1 i2) '(t)) + ((< i2 i1) '(nil)))))))) + (i1 '(t)) + (i2 '(nil)) + (t nil)))) + +(defun bmkp-info-position-cp (b1 b2) + "True if bookmark B1 sorts as Info bookmark before B2 in book order. +Return nil if neither sorts before the other. + +Two Info bookmarks are compared first by manual name, then by position +in the file. + +If `bmkp-info-sort-ignores-directories-flag' is non-nil then manual +names are used. If it is nil then absolute file names for the manuals +are used. + +True also if B1 is an Info bookmark but B2 is not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((i1 (bmkp-info-bookmark-p b1)) + (i2 (bmkp-info-bookmark-p b2)) + (fn (if bmkp-info-sort-ignores-directories-flag #'file-name-nondirectory #'abbreviate-file-name))) + (cond ((and i1 i2) + (setq i1 (funcall fn (bookmark-get-filename b1)) + i2 (funcall fn (bookmark-get-filename b2))) + (when case-fold-search (setq i1 (bmkp-upcase i1) + i2 (bmkp-upcase i2))) + (cond ((string-lessp i1 i2) '(t)) ; Compare manuals (file names). + ((string-lessp i2 i1) '(nil)) + (t ; Compare positions. + (setq i1 (bookmark-get-position b1) + i2 (bookmark-get-position b2)) + (cond ((or (not i1) (not i2)) '(t)) ; Fallback if no `position' entry. + ((<= i1 i2) '(t)) + ((< i2 i1) '(nil)))))) + (i1 '(t)) + (i2 '(nil)) + (t nil)))) + +(defun bmkp-gnus-cp (b1 b2) + "True if bookmark B1 sorts as a Gnus bookmark before B2. +Return nil if neither sorts before the other. + +Two Gnus bookmarks are compared first by Gnus group name, then by +article number, then by message ID. +True also if B1 is a Gnus bookmark but B2 is not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((g1 (bmkp-gnus-bookmark-p b1)) + (g2 (bmkp-gnus-bookmark-p b2))) + (cond ((and g1 g2) + (setq g1 (bookmark-prop-get b1 'group) + g2 (bookmark-prop-get b2 'group)) + (cond ((string-lessp g1 g2) '(t)) ; Compare groups. + ((string-lessp g2 g1) '(nil)) + (t ; Compare article numbers. + (setq g1 (bookmark-prop-get b1 'article) + g2 (bookmark-prop-get b2 'article)) + (cond ((< g1 g2) '(t)) + ((< g2 g1) '(nil)) + (t + (setq g1 (bookmark-prop-get b1 'message-id) + g2 (bookmark-prop-get b2 'message-id)) + (cond ((string-lessp g1 g2) '(t)) ; Compare message IDs. + ((string-lessp g2 g1) '(nil)) + (t nil))))))) + (g1 '(t)) + (g2 '(nil)) + (t nil)))) + +(defun bmkp-url-cp (b1 b2) + "True if bookmark B1 sorts as a URL bookmark before B2. +Return nil if neither sorts before the other. + +Two URL bookmarks are compared alphabetically, by their URLs. +True also if B1 is a URL bookmark but B2 is not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((u1 (bmkp-url-bookmark-p b1)) + (u2 (bmkp-url-bookmark-p b2))) + (cond ((and u1 u2) + (setq u1 (or (bookmark-prop-get b1 'location) (bookmark-get-filename b1)) + u2 (or (bookmark-prop-get b2 'location) (bookmark-get-filename b2))) + (cond ((string-lessp u1 u2) '(t)) + ((string-lessp u2 u1) '(nil)) + (t nil))) + (u1 '(t)) + (u2 '(nil)) + (t nil)))) + +;; Not used now. +(defun bmkp-w3m-cp (b1 b2) + "True if bookmark B1 sorts as a W3M URL bookmark before B2. +Return nil if neither sorts before the other. + +Two W3M URL bookmarks are compared alphabetically, by their URLs. +True also if B1 is a W3M bookmark but B2 is not. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((w1 (bmkp-w3m-bookmark-p b1)) + (w2 (bmkp-w3m-bookmark-p b2))) + (cond ((and w1 w2) + (setq w1 (bookmark-get-filename b1) + w2 (bookmark-get-filename b2)) + (cond ((string-lessp w1 w2) '(t)) + ((string-lessp w2 w1) '(nil)) + (t nil))) + (w1 '(t)) + (w2 '(nil)) + (t nil)))) + +(defun bmkp-position-cp (b1 b2) + "True if the `position' of B1 is not greater than that of B2. +Return nil if B1 and B2 do not bookmark the same buffer or they have +the same `position' value. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((buf1 (bmkp-get-buffer-name b1)) + (buf2 (bmkp-get-buffer-name b2))) + (and buf1 buf2 (equal buf1 buf2) + (let ((i1 (bookmark-get-position b1)) + (i2 (bookmark-get-position b2))) + (cond ((or (not i1) (not i2)) '(t)) ; Fallback if no `position' entry. + ((<= i1 i2) '(t)) + ((< i2 i1) '(nil))))))) + +(defun bmkp-alpha-cp (b1 b2) + "True if bookmark B1's name sorts alphabetically before B2's. +Return nil if neither sorts before the other. + +The bookmark names are compared, respecting `case-fold-search'. +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((s1 (car b1)) + (s2 (car b2))) + (when case-fold-search (setq s1 (bmkp-upcase s1) + s2 (bmkp-upcase s2))) + (cond ((string-lessp s1 s2) '(t)) + ((string-lessp s2 s1) '(nil)) + (t nil)))) + +;; Do not use `bmkp-make-plain-predicate', because it falls back on `bookmark-alpha-p'. +;; Return nil if `bookmark-alpha-cp' cannot decide. +(defun bmkp-alpha-p (b1 b2) + "True if bookmark B1's name sorts alphabetically before B2's. +The bookmark names are compared, respecting `case-fold-search'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (car (bmkp-alpha-cp b1 b2))) + + +;;(@* "Sorting - File-Name Predicates") +;; *** Sorting - File-Name Predicates *** + +(defun bmkp-file-alpha-cp (b1 b2) + "True if bookmark B1's file name sorts alphabetically before B2's. +Return nil if neither sorts before the other. + +The file names are shortened using `abbreviate-file-name', then they +are compared respecting `case-fold-search'. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (let ((f1 (bmkp-file-bookmark-p b1)) + (f2 (bmkp-file-bookmark-p b2))) + (cond ((and f1 f2) + ;; Call `abbreviate-file-name' mainly to get letter case right per platform. + (setq f1 (abbreviate-file-name (bookmark-get-filename b1)) + f2 (abbreviate-file-name (bookmark-get-filename b2))) + (when case-fold-search (setq f1 (bmkp-upcase f1) + f2 (bmkp-upcase f2))) + (cond ((string-lessp f1 f2) '(t)) + ((string-lessp f2 f1) '(nil)) + (t nil))) + (f1 '(t)) + (f2 '(nil)) + (t nil)))) + +;; We define all file-attribute predicates, in case you want to use them. +;; +;; `bmkp-file-attribute-0-cp' - type +;; `bmkp-file-attribute-1-cp' - links +;; `bmkp-file-attribute-2-cp' - uid +;; `bmkp-file-attribute-3-cp' - gid +;; `bmkp-file-attribute-4-cp' - last access time +;; `bmkp-file-attribute-5-cp' - last update time +;; `bmkp-file-attribute-6-cp' - last status change +;; `bmkp-file-attribute-7-cp' - size +;; `bmkp-file-attribute-8-cp' - modes +;; `bmkp-file-attribute-9-cp' - gid change +;; `bmkp-file-attribute-10-cp' - inode +;; `bmkp-file-attribute-11-cp' - device +;; +(bmkp-define-file-sort-predicate 0) ; Type: file, symlink, dir +(bmkp-define-file-sort-predicate 1) ; Links +(bmkp-define-file-sort-predicate 2) ; Uid +(bmkp-define-file-sort-predicate 3) ; Gid +(bmkp-define-file-sort-predicate 4) ; Last access time +(bmkp-define-file-sort-predicate 5) ; Last modification time +(bmkp-define-file-sort-predicate 6) ; Last status-change time +(bmkp-define-file-sort-predicate 7) ; Size +(bmkp-define-file-sort-predicate 8) ; Modes +(bmkp-define-file-sort-predicate 9) ; Gid would change if re-created +(bmkp-define-file-sort-predicate 10) ; Inode +(bmkp-define-file-sort-predicate 11) ; Device + +(defun bmkp-local-file-accessed-more-recently-cp (b1 b2) + "True if bookmark B1's local file was accessed more recently than B2's. +Return nil if neither sorts before the other. + +A local file sorts before a remote file, which sorts before other +bookmarks. Two remote files are considered incomparable - their +access times are not examined. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (cond ((and (bmkp-local-file-bookmark-p b1) (bmkp-local-file-bookmark-p b2)) + (bmkp-cp-not (bmkp-file-attribute-4-cp b1 b2))) + ((bmkp-local-file-bookmark-p b1) '(t)) + ((bmkp-local-file-bookmark-p b2) '(nil)) + ((and (bmkp-remote-file-bookmark-p b1) + (bmkp-remote-file-bookmark-p b2)) nil) + ((bmkp-remote-file-bookmark-p b1) '(t)) + ((bmkp-remote-file-bookmark-p b2) '(nil)) + (t nil))) + +(defun bmkp-local-file-updated-more-recently-cp (b1 b2) + "True if bookmark B1's local file was updated more recently than B2's. +Return nil if neither sorts before the other. + +A local file sorts before a remote file, which sorts before other +bookmarks. Two remote files are considered incomparable - their +update times are not examined. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (cond ((and (bmkp-local-file-bookmark-p b1) (bmkp-local-file-bookmark-p b2)) + (bmkp-cp-not (bmkp-file-attribute-5-cp b1 b2))) + ((bmkp-local-file-bookmark-p b1) '(t)) + ((bmkp-local-file-bookmark-p b2) '(nil)) + ((and (bmkp-remote-file-bookmark-p b1) + (bmkp-remote-file-bookmark-p b2)) nil) + ((bmkp-remote-file-bookmark-p b1) '(t)) + ((bmkp-remote-file-bookmark-p b2) '(nil)) + (t nil))) + +(defun bmkp-local-file-size-cp (b1 b2) + "True if bookmark B1's local file is larger than B2's. +Return nil if neither sorts before the other. + +A local file sorts before a remote file, which sorts before other +bookmarks. Two remote files are considered incomparable - their +sizes are not examined. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (cond ((and (bmkp-local-file-bookmark-p b1) (bmkp-local-file-bookmark-p b2)) + (bmkp-cp-not (bmkp-file-attribute-7-cp b1 b2))) + ((bmkp-local-file-bookmark-p b1) '(t)) + ((bmkp-local-file-bookmark-p b2) '(nil)) + ((and (bmkp-remote-file-bookmark-p b1) + (bmkp-remote-file-bookmark-p b2)) nil) + ((bmkp-remote-file-bookmark-p b1) '(t)) + ((bmkp-remote-file-bookmark-p b2) '(nil)) + (t nil))) + +(defun bmkp-local-file-type-cp (b1 b2) + "True if bookmark B1 sorts by local file type before B2. +Return nil if neither sorts before the other. + +For two local files, a file sorts before a symlink, which sorts before +a directory. + +A local file sorts before a remote file, which sorts before other +bookmarks. Two remote files are considered incomparable - their file +types are not examined. + +Reverse the roles of B1 and B2 for a false value. +A true value is returned as `(t)', a false value as `(nil)'. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + (setq b1 (bmkp-get-bookmark b1) + b2 (bmkp-get-bookmark b2)) + (cond ((and (bmkp-local-file-bookmark-p b1) (bmkp-local-file-bookmark-p b2)) + (bmkp-file-attribute-0-cp b1 b2)) + ((bmkp-local-file-bookmark-p b1) '(t)) + ((bmkp-local-file-bookmark-p b2) '(nil)) + ((and (bmkp-remote-file-bookmark-p b1) + (bmkp-remote-file-bookmark-p b2)) nil) + ((bmkp-remote-file-bookmark-p b1) '(t)) + ((bmkp-remote-file-bookmark-p b2) '(nil)) + (t nil))) + +(defun bmkp-cp-not (truth) + "Return the negation of boolean value TRUTH. +If TRUTH is (t), return (nil), and vice versa. +If TRUTH is nil, return nil." + (and truth (if (car truth) '(nil) '(t)))) + + +;;(@* "Indirect Bookmarking Functions") +;; *** Indirect Bookmarking Functions *** + +;;;###autoload (autoload 'bmkp-url-target-set "bookmark+") +(defun bmkp-url-target-set (url &optional arg name/prefix no-overwrite-p no-refresh-p msg-p) + ; Bound globally to `C-x x c u'. + "Set a bookmark for a URL. Return the bookmark. +Interactively you are prompted for the URL. Completion is available. +Use `M-n' to pick up the url at point as the default. + +You are also prompted for the bookmark name. But with a non-negative +prefix arg, you are prompted only for a bookmark-name prefix. In that +case, the bookmark name is the prefix followed by the URL. + +When entering a bookmark name you can use completion against existing +names. This completion is lax, so you can easily edit an existing +name. See `bookmark-set' for particular keys available during this +input. + +If you use a numeric prefix arg, such as `C-1', instead of plain +`C-u', then a new bookmark is created if a bookmark of the same name +already exists: an existing bookmark is not overwritten. You can thus +have multiple bookmarks with the same name, which target different +URLs. + +Summary of prefix argument behavior: + +* None: Provide full bookmark name. Overwrite existing bookmark +* Plain `C-u': Provide name prefix only. Overwrite existing bookmark +* N >= 0: Provide name prefix only. Do not overwrite. +* N < 0: Provide full bookmark name. Do not overwrite. + +Non-interactively: +* Numeric ARG >= 0 means NAME/PREFIX is a bookmark-name prefix. +* NAME/PREFIX is the bookmark name or its prefix (the suffix = URL). +* Non-nil NO-OVERWRITE-P means do not overwrite an existing bookmark. +* Non-nil NO-REFRESH-P means do not refresh/rebuild the bookmark-list + display. +* Non-nil MSG-P means display a status message." + (interactive + (let* ((icicle-unpropertize-completion-result-flag t) + (default-url (or (bmkp-thing-at-point 'url) + (and (fboundp 'url-get-url-at-point) + (url-get-url-at-point)) + ;; TEMPORARY hack to work around Emacs bug #44822. + "https://example.com")) + (parg current-prefix-arg) + (prefix-only (and parg (natnump (prefix-numeric-value parg)))) + (no-overw (and parg (atom current-prefix-arg)))) + (list (if (require 'ffap nil t) + (ffap-read-file-or-url "URL: " default-url) + (read-from-minibuffer "URL: " nil nil nil nil default-url)) + prefix-only + (if prefix-only + (read-string "Prefix for bookmark name: ") + (bmkp-completing-read-lax "Bookmark name")) + no-overw + nil + 'MSG))) + (unless name/prefix (setq name/prefix "")) + (let ((bookmark-make-record-function (cond ((and (eq major-mode 'eww-mode) + (fboundp 'bmkp-make-eww-record)) ; Emacs 25+ + 'bmkp-make-eww-record) + ((eq major-mode 'w3m-mode) 'bmkp-make-w3m-record) + (t `(lambda () (bmkp-make-url-browse-record ',url))))) + bmk failure) + (condition-case err + (setq bmk (bookmark-store (if arg (concat name/prefix url) name/prefix) + (cdr (bookmark-make-record)) no-overwrite-p no-refresh-p (not msg-p))) + (error (setq failure err))) + (when failure (error "Failed to create bookmark for `%s':\n%s\n" url failure)) + bmk)) ; Return the bookmark. + +;;;###autoload (autoload 'bmkp-file-target-set "bookmark+") +(defun bmkp-file-target-set (file &optional arg name/prefix no-overwrite no-refresh-p msg-p) + ; Bound to `C-x x c f' + "Set a bookmark for FILE. Return the bookmark. +The bookmarked position is the beginning of the file (0). +Interactively you are prompted for FILE. Completion is available. +You can use `M-n' to pick up the file name at point, or if none then +the visited file. + +FILE can also be a directory name. In that case set a bookmark for +the directory. + +You are also prompted for the bookmark name. But with a non-negative +prefix arg, you are prompted only for a bookmark-name prefix. In that +case, the bookmark name is the prefix followed by the nondirectory +part of FILE (or of its `directory-file-name', if a directory name). + +When entering a bookmark name you can use completion against existing +names. This completion is lax, so you can easily edit an existing +name. See `bookmark-set' for particular keys available during this +input. + +If you use a numeric prefix arg, such as `C-1', instead of plain +`C-u', then a new bookmark is created if a bookmark of the same name +already exists: an existing bookmark is not overwritten. You can thus +have multiple bookmarks with the same name, which target different +URLs. + +Summary of prefix argument behavior: + +* None: Provide full bookmark name. Overwrite existing bookmark +* Plain `C-u': Provide name prefix only. Overwrite existing bookmark +* N >= 0: Provide name prefix only. Do not overwrite. +* N < 0: Provide full bookmark name Do not overwrite. + +Non-interactively: +* Numeric ARG >= 0 means NAME/PREFIX is a bookmark-name prefix. +* NAME/PREFIX is the bookmark name or its prefix. +* Non-nil NO-OVERWRITE-P means do not overwrite an existing bookmark. +* Non-nil NO-REFRESH-P means do not refresh/rebuild the bookmark-list + display. +* Non-nil MSG-P means show a warning message if file does not exist." + (interactive + (let* ((icicle-unpropertize-completion-result-flag t) + (parg current-prefix-arg) + (prefix-only (and parg (natnump (prefix-numeric-value parg)))) + (no-overw (and parg (atom current-prefix-arg)))) + (list (read-file-name "File: " nil + (or (if (boundp 'file-name-at-point-functions) ; In `files.el', Emacs 23.2+. + (run-hook-with-args-until-success 'file-name-at-point-functions) + (bmkp-ffap-guesser)) + (bmkp-thing-at-point 'filename) + (buffer-file-name))) + prefix-only + (if prefix-only + (read-string "Prefix for bookmark name: ") + (bmkp-completing-read-lax "Bookmark name")) + no-overw + nil + 'MSG))) + (unless name/prefix (setq name/prefix "")) + (let ((bookmark-make-record-function (bmkp-make-record-for-target-file file)) + bmk failure) + (condition-case err + (setq bmk (bookmark-store (if arg + (concat name/prefix + (file-name-nondirectory (if (file-directory-p file) + (directory-file-name file) + file))) + name/prefix) + (cdr (bookmark-make-record)) no-overwrite no-refresh-p (not msg-p))) + (error (setq failure (error-message-string err)))) + (when failure (error "Failed to create bookmark for `%s':\n%s\n" file failure)) + (unless no-refresh-p (bmkp-refresh/rebuild-menu-list bmk (not msg-p))) + (when (and msg-p (not (file-exists-p file))) + (message "File name is now bookmarked, but no such file yet: `%s'" (expand-file-name file))) + bmk)) ; Return the bookmark. + +(defun bmkp-make-record-for-target-file (file) + "Return a function that creates a bookmark record for FILE. +The bookmarked position will be the beginning of the file." + ;; $$$$$$ Maybe need a way to bypass default handler, at least for autofiles. + ;; Doesn't seem to make much sense to use a handler such as a shell cmd in this context. (?) + (set-text-properties 0 (length file) () file) + (let ((default-handler (condition-case nil (bmkp-default-handler-for-file file) (error nil))) + (common `((filename . ,file) + (position . 0) + (created . ,(current-time))))) + (cond (default-handler ; User default handler + `(lambda () ',(append common `((file-handler . ,default-handler))))) + ;; Non-user defaults. + ((and (require 'image nil t) (require 'image-mode nil t) ; Image + (condition-case nil (image-type file) (error nil))) + ;; Last two lines of function are from `image-bookmark-make-record'. + ;; But don't use that directly, because it uses + ;; `bookmark-make-record-default', which gets nil for `filename'. + + ;; NEED TO KEEP THIS CODE SYNC'D WITH `diredp-bookmark'. + `(lambda () + ',(append common `((image-type . ,(image-type file)) (handler . image-bookmark-jump))))) + ((let ((case-fold-search t)) (bmkp-string-match-p "\\([.]au$\\|[.]wav$\\)" file)) ; Sound + ;; Obsolete: `(lambda () '((filename . ,file) (handler . bmkp-sound-jump)))) + `(lambda () ',(append common '((file-handler . play-sound-file))))) + (t + `(lambda () ',common))))) + +(when (fboundp 'file-cache-add-file) + (defadvice file-cache-add-file (around bmkp-autofile-filecache activate) + "Respect option `bmkp-autofile-filecache'." + (cond ((eq bmkp-autofile-filecache 'autofile-only) + (bmkp-autofile-set + (ad-get-arg 0) nil nil + 'NO-REFRESH-P)) + ((eq bmkp-autofile-filecache 'autofile+cache) + (progn + ad-do-it + (bmkp-autofile-set + (ad-get-arg 0) nil nil + 'NO-REFRESH-P 'MSG-P))) + ((eq bmkp-autofile-filecache 'cache-only) + ad-do-it)))) + +(defun bmkp-find-file-invoke-bookmark-if-autofile () + "Invoke the autofile bookmark associated with the visited file. +This is added to `find-file-hook' when option +`bmkp-autofile-access-invokes-bookmark-flag' is non-nil. When invoked +it causes regular file access to invoke the associated bookmark. This +has the effect of updating the bookmark data, such as the number of +visits." + (let* ((buf-file (buffer-file-name)) + (bmk (bmkp-get-bookmark-in-alist (file-name-nondirectory buf-file) + t + (bmkp-autofile-alist-only))) + (bmk-file (and bmk (bookmark-get-filename bmk)))) + (when (and bmk-file (bmkp-same-file-p buf-file bmk-file)) + (let ((bmkp-autofile-access-invokes-bookmark-flag nil)) ; Just to be sure. + (bookmark--jump-via bmk 'ignore))))) + +;;;###autoload (autoload 'bmkp-bookmark-a-file "bookmark+") +(defalias 'bmkp-bookmark-a-file 'bmkp-autofile-set) +;;;###autoload (autoload 'bmkp-autofile-set "bookmark+") +(defun bmkp-autofile-set (file &optional dir prefix no-refresh-p msg-p) ; Bound to `C-x x c a' + "Set a bookmark for FILE, autonaming the bookmark for the file. +Return the bookmark. +Interactively, you are prompted for FILE. You can use `M-n' to pick +up the file name at point or the visited file. + +The bookmark name is the nondirectory part of FILE, but with a prefix +arg you are also prompted for a PREFIX string to prepend to the +bookmark name. The bookmarked position is the beginning of the file. + +Note that if you provide PREFIX then the bookmark will not satisfy +`bmkp-autofile-bookmark-p' unless you provide the same PREFIX to that +predicate. + +The bookmark's file name is FILE if absolute. If relative then it is +FILE expanded in DIR, if non-nil, or in the current directory +\(`default-directory'). + +If a bookmark with the same name already exists for the same file name +then do nothing. + +Otherwise, create a new bookmark for the file, even if a bookmark with +the same name already exists. This means that you can have more than +one autofile bookmark with the same bookmark name and the same +relative file name (nondirectory part), but with different absolute +file names. + +Non-interactively: + - Non-nil NO-REFRESH-P means do not refresh/rebuild the bookmark-list + display. + - Non-nil optional arg MSG-P means display status messages." + (interactive + (list (let ((icicle-unpropertize-completion-result-flag t)) + (read-file-name "File: " nil + (if (or (> emacs-major-version 23) + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (let ((deflts ()) + def) + (when (setq def (buffer-file-name)) (push def deflts)) + (when (setq def (bmkp-thing-at-point 'filename)) (push def deflts)) + (when (setq def (bmkp-ffap-guesser)) (push def deflts)) + (when (and (boundp 'file-name-at-point-functions) + (setq def (run-hook-with-args-until-success + 'file-name-at-point-functions))) + (push def deflts)) + deflts) + (or (if (boundp 'file-name-at-point-functions) ; In `files.el', Emacs 23.2+. + (run-hook-with-args-until-success 'file-name-at-point-functions) + (bmkp-ffap-guesser)) + (bmkp-thing-at-point 'filename) + (buffer-file-name))))) + nil + (and current-prefix-arg (read-string "Prefix for bookmark name: ")) + nil + 'MSG)) + (let* ((dir-to-use (if (file-name-absolute-p file) + (file-name-directory file) + (or dir default-directory))) + ;; Look for existing bookmark with same name, same file, in `dir-to-use'. + (bmk (bmkp-get-autofile-bookmark file dir-to-use prefix))) + ;; If BMK was found, then instead of doing nothing we could replace the existing BMK with a new + ;; one, as follows: + ;; (let ((bookmark-make-record-function (bmkp-make-record-for-target-file file))) + ;; (bmkp-replace-existing-bookmark bmk)) ; Update the existing bookmark. + (if (not bmk) + ;; Create a new bookmark, and return it. + (bmkp-file-target-set (expand-file-name file dir-to-use) t prefix 'NO-OVERWRITE no-refresh-p msg-p) + (when msg-p (message "Autofile bookmark set for `%s'" file)) + bmk))) ; Return the bookmark. + +(defun bmkp-get-autofile-bookmark (file &optional dir prefix) + "Return an existing autofile bookmark for FILE, or nil if there is none. +The bookmark name is PREFIX prepended to the nondirectory part of +FILE (or of FILE's `directory-file-name', if FILE is a directory). + +If PREFIX is nil then it acts like an empty prefix (\"\"). + +The directory part of bookmark entry `filename' is the directory part +of FILE, if FILE is absolute. Otherwise, it is DIR, if non-nil, or +`default-directory' otherwise. + +FILE and the `filename' entry of the bookmark returned are the same, +except possibly for their directory parts (see previous)." + (let* ((fname (file-name-nondirectory (if (file-directory-p file) + (directory-file-name file) + file))) + (bname (if prefix (concat prefix fname) fname)) + (dir-to-use (if (file-name-absolute-p file) + (file-name-directory file) + (or dir default-directory)))) + ;; Look for existing bookmark with same name, same file, in `dir-to-use'. + (catch 'bmkp-get-autofile-bookmark + (dolist (bmk bookmark-alist) + (when (string= bname (bmkp-bookmark-name-from-record bmk)) + (let* ((bfil (bookmark-get-filename bmk)) + (bdir (and bfil (file-name-directory bfil)))) + (when (and bfil bdir (bmkp-same-file-p bdir dir-to-use) (bmkp-same-file-p bfil file)) + (throw 'bmkp-get-autofile-bookmark bmk))))) ; Return the bookmark. + nil))) + +;;;###autoload (autoload 'bmkp-tag-a-file "bookmark+") +(defalias 'bmkp-tag-a-file 'bmkp-autofile-add-tags) ; Bound to `C-x x t + a' +;;;###autoload (autoload 'bmkp-autofile-add-tags "bookmark+") +(defun bmkp-autofile-add-tags (file tags &optional dir prefix no-update-p msg-p) + "Add TAGS to the autofile bookmark for FILE (a file or directory name). +Return the number of tags added. + +If there is no autofile bookmark for FILE, create one. +Interactively, you are prompted for FILE and then TAGS. +When prompted for FILE you can use `M-n' to pick up the file name at +point, or if none then the visited file. + +With a non-negative prefix argument, you are prompted for a file-name +prefix, as in `bmkp-autofile-set'. + +When prompted for tags, hit `RET' to enter each tag, then hit `RET' +again after the last tag. You can use completion to enter each tag. +Completion is lax: you are not limited to existing tags. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a non-positive prefix argument if you want to refresh them. + +Non-interactively: + - TAGS is a list of strings. + - DIR and PREFIX are as for `bmkp-autofile-set'. + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + - Non-nil MSG-P means display a message about the addition." + (interactive + (list (let ((icicle-unpropertize-completion-result-flag t)) + (read-file-name "File or directory to tag: " nil + (or (if (boundp 'file-name-at-point-functions) ; In `files.el', Emacs 23.2+. + (run-hook-with-args-until-success 'file-name-at-point-functions) + (bmkp-ffap-guesser)) + (bmkp-thing-at-point 'filename) + (buffer-file-name)))) + (bmkp-read-tags-completing nil nil (and current-prefix-arg + (<= (prefix-numeric-value current-prefix-arg) 0))) + nil + (and current-prefix-arg (wholenump (prefix-numeric-value current-prefix-arg)) + (read-string "Prefix for bookmark name: ")) + nil + 'MSG)) + (bmkp-add-tags (bmkp-autofile-set file dir prefix no-update-p) tags no-update-p msg-p)) + +;;;###autoload (autoload 'bmkp-untag-a-file "bookmark+") +(defalias 'bmkp-untag-a-file 'bmkp-autofile-remove-tags) ; Bound to `C-x x t - a' +;;;###autoload (autoload 'bmkp-autofile-remove-tags "bookmark+") +(defun bmkp-autofile-remove-tags (file tags &optional dir prefix no-update-p msg-p) + "Remove TAGS from autofile bookmark for FILE. +Return the number of tags removed. + +Interactively, you are prompted for TAGS and then FILE. +With Emacs 22 and later, only files with at least one of the given +tags are candidates. + +When prompted for FILE you can use `M-n' to pick up the file name at +point, or if none then the visited file. + +With a non-negative prefix argument, you are prompted for a file-name +prefix, as in `bmkp-autofile-set'. + + +When prompted for tags, hit `RET' to enter each tag to be removed, +then hit `RET' again after the last tag. You can use completion to +enter each tag. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a non-positive prefix argument if you want to refresh them. + +Non-interactively: + - TAGS is a list of strings. + - DIR and PREFIX are as for `bmkp-autofile-set'. + - Non-nil NO-UPDATE-P means do not update `bmkp-tags-alist', do not + update the modification count and maybe save bookmarks, and do not + refresh/rebuild the bookmark-list display + - Non-nil MSG-P means display a message about the removal." + (interactive + (lexical-let* ((pref + (and current-prefix-arg (wholenump (prefix-numeric-value current-prefix-arg)) + (read-string "Prefix for bookmark name: "))) + (tgs + (bmkp-read-tags-completing nil nil (and current-prefix-arg + (<= (prefix-numeric-value current-prefix-arg) 0)))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (fil (condition-case nil + (read-file-name + "File: " nil + (or (if (boundp 'file-name-at-point-functions) ; In `files.el', Emacs 23.2+. + (run-hook-with-args-until-success 'file-name-at-point-functions) + (bmkp-ffap-guesser)) + (bmkp-thing-at-point 'filename) + (buffer-file-name)) + t nil (lambda (ff) ; PREDICATE - only for Emacs 22+. + (let* ((bmk (bmkp-get-autofile-bookmark ff nil pref)) + (btgs (and bmk (bmkp-get-tags bmk)))) + (and btgs (catch 'bmkp-autofile-remove-tags-pred + (dolist (tag tgs) + (when (not (member tag btgs)) + (throw 'bmkp-autofile-remove-tags-pred nil))) + t))))) + (error (read-file-name "File: " nil (or (bmkp-ffap-guesser) + (bmkp-thing-at-point 'filename) + (buffer-file-name))))))) + (list fil tgs nil pref nil 'MSG))) + (bmkp-remove-tags (bmkp-autofile-set file dir prefix no-update-p) tags no-update-p msg-p)) + +;;;###autoload (autoload 'bmkp-purge-notags-autofiles "bookmark+") +(defun bmkp-purge-notags-autofiles (&optional prefix msg-p) ; Not bound + "Delete all autofile bookmarks that have no tags. +With a prefix arg, you are prompted for a PREFIX for the bookmark name. +Non-interactively, non-nil MSG-P means display a status message." + (interactive (if (not (y-or-n-p "Delete all autofile bookmarks that do not have tags? ")) + (error "OK - deletion canceled") + (list (and current-prefix-arg (read-string "Prefix for bookmark name: ")) 'MSG))) + (let ((bmks (bmkp-autofile-alist-only prefix)) + (bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag)) ; Save only after `dolist'. + record tags) + ;; Needs Bookmark+ version of `bookmark-delete', which accepts a bookmark, not just its name. + (dolist (bmk bmks) + (when (and (setq tags (assq 'tags (bmkp-bookmark-data-from-record bmk))) + (or (not tags) (null (cdr tags)))) + (bookmark-delete bmk 'BATCHP)))) ; Do not refresh list here - do it after iterate. + (bmkp-tags-list) ; Update the tags cache now, after iterate. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh/rebuild-menu-list nil (not msg-p))) ; Refresh now, after iterate. + + +;; $$$$$$ Not used currently. +(defun bmkp-replace-existing-bookmark (bookmark) + "Replace existing BOOKMARK with a new one of the same name. +Return the new bookmark. +BOOKMARK is a full bookmark record, not a bookmark name. + +This replaces the existing bookmark data with the data for a new +bookmark, based on `bookmark-make-record-function'. It also updates +the `bmkp-full-record' on the bookmark name (without otherwise +changing the name)." + (let (failure) + (condition-case err + (progn ; Code similar to `bookmark-store'. + (setcdr bookmark (cdr (bookmark-make-record))) + (bmkp-maybe-save-bookmarks) + ;; Put the full bookmark on its name as property `bmkp-full-record'. + ;; Do this regardless of Emacs version and `bmkp-propertize-bookmark-names-flag'. + ;; If it needs to be stripped, that will be done when saving. + (let ((bname (bmkp-bookmark-name-from-record bookmark))) + (put-text-property 0 (length bname) 'bmkp-full-record bookmark bname) + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bookmark bmkp-modified-bookmarks) + (setq bmkp-modified-bookmarks (cons bookmark bmkp-modified-bookmarks))) + (setq bookmark-current-bookmark bname)) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P)) + (error (setq failure (error-message-string err)))) + (if (not failure) + bookmark ; Return the bookmark. + (error "Failed to update bookmark `%s':\n%s\n" + (bmkp-bookmark-name-from-record bookmark) failure)))) + +(defun bmkp-default-handler-for-file (filename) + "Return a default bookmark handler for FILENAME, or nil. +If non-nil, it is a Lisp function, determined as follows: + +1. Match FILENAME against `bmkp-default-handlers-for-file-types'. If +it matches a Lisp function, return that function. If it matches a +shell command, return a Lisp function that invokes that shell command. + +2. If no match is found and `bmkp-guess-default-handler-for-file-flag' +is non-nil, then try to find an appropriate shell command using, in +order, `dired-guess-default' and `mailcap-file-default-commands' +\(Emacs 23+ only). If a match is found then return a Lisp function +that invokes that shell command." + (let* ((bmkp-user (bmkp-default-handler-user filename)) + (shell-cmd (if (stringp bmkp-user) + bmkp-user + (and (not bmkp-user) + bmkp-guess-default-handler-for-file-flag + (or (and (require 'dired-x nil t) + (let* ((case-fold-search + (or (and (boundp 'dired-guess-shell-case-fold-search) + dired-guess-shell-case-fold-search) + case-fold-search)) + (default (dired-guess-default (list filename)))) + (if (consp default) (car default) default))) + (and (require 'mailcap nil t) ; Emacs 23+ + (car (mailcap-file-default-commands (list filename))))))))) + (cond ((stringp shell-cmd) `(lambda (bmk) (dired-do-shell-command ',shell-cmd nil ',(list filename)))) + ((or (functionp bmkp-user) (and bmkp-user (symbolp bmkp-user))) + bmkp-user) + (t nil)))) + +(defun bmkp-default-handler-user (filename) + "Return default handler for FILENAME. +The value is based on `bmkp-default-handlers-for-file-types'." + (catch 'bmkp-default-handler-user + (dolist (assn bmkp-default-handlers-for-file-types) + (when (bmkp-string-match-p (car assn) filename) (throw 'bmkp-default-handler-user (cdr assn)))) + nil)) + +;; Keep this only for compatibility with existing bookmarks that have `bmkp-sound-jump' as `handler' prop. +(defun bmkp-sound-jump (bookmark) + "Handler for sound files: play the sound file that is BOOKMARK's file. +This is deprecated. It is kept only for old bookmarks that already +use this as the `handler' entry. New sound bookmarks use +`play-sound-file' as entry `file-handler'." + (play-sound-file (bookmark-get-filename bookmark))) + +(when (> emacs-major-version 21) + (defun bmkp-compilation-target-set (&optional prefix) ; Bound to `C-c C-b' in compilation mode + "Set a bookmark at the start of the line for this compilation hit. +The bookmark is set in the indicated file at the indicated line. +You are prompted for the bookmark name. But with a prefix arg, you +are prompted only for a PREFIX string. In that case, and in Lisp +code, the bookmark name is PREFIX followed by the (relative) file name +of the hit, followed by the line number of the hit." + (interactive "P") + (let* ((file+line (bmkp-compilation-file+line-at (line-beginning-position))) + (file (car file+line)) + (line (cdr file+line))) + (unless (and file line) (error "Cursor is not on a compilation hit")) + (save-excursion + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) (forward-line (1- line)) + (if (not prefix) + (call-interactively #'bookmark-set) + (when (interactive-p) + (setq prefix (read-string "Prefix for bookmark name: "))) + (unless (stringp prefix) (setq prefix "")) + (bookmark-set (format "%s%s, line %s" prefix (file-name-nondirectory file) line) + 99 'INTERACTIVEP)))))) + + (defun bmkp-compilation-file+line-at (&optional pos) + "Return the file and position indicated by this compilation message. +These are returned as a cons: (FILE . POSITION). +POSITION is the beginning of the line indicated by the message." + (unless pos (setq pos (point))) + (let* ((loc (car (get-text-property pos 'message))) + (line (cadr loc)) + (filename (caar (nth 2 loc))) + (directory (cadr (car (nth 2 loc)))) + (spec-dir (if directory (expand-file-name directory) default-directory))) + (cons (expand-file-name filename spec-dir) line)))) + +(when (> emacs-major-version 21) + (defun bmkp-compilation-target-set-all (prefix &optional msg-p) ; Bound to `C-c C-M-b' in compilation mode + "Set a bookmark for each hit of a compilation buffer. +NOTE: You can use `C-x C-q' to make the buffer writable and then + remove any hits that you do not want to bookmark. Only the hits + remaining in the buffer are bookmarked. + +Interactively, you are prompted for a PREFIX string to prepend to each +bookmark name, the rest of which is the file name of the hit followed +by its line number. +Non-interactively, non-nil optional arg MSG-P means prompt and display +status messages." + (interactive (list (read-string "Prefix for bookmark name: ") 'MSG)) + (when (and msg-p (not (y-or-n-p "This will bookmark *EACH* hit in the buffer. Continue? "))) + (error "OK - canceled")) + (let ((count 0)) + (save-excursion + (goto-char (point-min)) + (when (get-text-property (point) 'message) ; Visible part of buffer starts with a hit + (condition-case nil ; because buffer is narrowed or header text otherwise removed. + (bmkp-compilation-target-set prefix) ; Ignore error here (e.g. killed buffer). + (error nil)) + (setq count (1+ count))) + (while (and (condition-case nil (progn (compilation-next-error 1) t) (error nil)) + (not (eobp))) + (condition-case nil + (bmkp-compilation-target-set prefix) ; Ignore error here (e.g. killed buffer). + (error nil)) + (setq count (1+ count))) + (when msg-p (message "Set %d bookmarks" count)))))) + + +;; We could make the `occur' code work for Emacs 20 & 21 also, but you would not be able to +;; delete some occurrences and bookmark only the remaining ones. + +(when (> emacs-major-version 21) + (defun bmkp-occur-target-set (&optional prefix) ; Bound to `C-c C-b' in Occur mode + "Set a bookmark at the start of the line for this `(multi-)occur' hit. +You are prompted for the bookmark name. But with a prefix arg, you +are prompted only for a PREFIX string. In that case, and in Lisp +code, the bookmark name is PREFIX followed by the buffer name of the +hit, followed by the line number of the hit. + +You can use this only in `Occur' mode (commands such as `occur' and +`multi-occur')." + (interactive "P") + (unless (eq major-mode 'occur-mode) (error "You must be in `occur-mode'")) + (let* ((line (and prefix + (save-excursion + (forward-line 0) + ;; We could use [: ] here, to handle `moccur', but that loses anyway for + ;; `occur-mode-find-occurrence', so we would need other hoops too. + (re-search-forward "^\\s-+\\([0-9]+\\):" (line-end-position) 'NOERROR) + (or (format "%5d" (string-to-number (match-string 1))) "")))) + (mkr (occur-mode-find-occurrence)) + (buf (marker-buffer mkr))) + (save-excursion (with-current-buffer buf + (goto-char mkr) + (if (not prefix) + (call-interactively #'bookmark-set) + (when (interactive-p) + (setq prefix (read-string "Prefix for bookmark name: "))) + (unless (stringp prefix) (setq prefix "")) + (bookmark-set (format "%s%s, line %s" prefix buf line) 99 'INTERACTIVEP))))))) + +(when (> emacs-major-version 21) + (defun bmkp-occur-target-set-all (&optional prefix msg-p) ; Bound to `C-c C-M-b' in Occur mode + "Set a bookmark for each hit of a `(multi-)occur' buffer. +NOTE: You can use `C-x C-q' to make the buffer writable and then + remove any hits that you do not want to bookmark. Only the hits + remaining in the buffer are bookmarked. + +Interactively, you are prompted for a PREFIX string to prepend to each +bookmark name, the rest of which is the buffer name of the hit +followed by its line number. + +You can use this only in `Occur' mode (commands such as `occur' and +`multi-occur'). + +See also command `bmkp-occur-create-autonamed-bookmarks', which +creates autonamed bookmarks to all `occur' and `multi-occur' hits. + +Non-interactively, non-nil MSG-P means prompt and show status +messages." + (interactive (list (read-string "Prefix for bookmark name: ") 'MSG)) + (when (and msg-p (not (y-or-n-p "This will bookmark *EACH* hit in the buffer. Continue? "))) + (error "OK - canceled")) + (let ((count 0)) + (save-excursion + (goto-char (point-min)) + (while (condition-case nil + (progn (occur-next) t) ; "No more matches" ends loop. + (error nil)) + (condition-case nil + (bmkp-occur-target-set prefix) ; Ignore error here (e.g. killed buffer). + (error nil)) + (setq count (1+ count))) + (when msg-p (message "Set %d bookmarks" count)))))) + + +;;(@* "Bookmark Links") +;; *** Bookmark Links *** + +(when (> emacs-major-version 21) + + (defun bmkp-bookmark-linked-at (&optional position msgp) + "Return the bookmark linked at POSITION (default: point), or nil if none." + (interactive "d\np") + (unless position (setq position (point))) + (let ((bmk (get-text-property position 'bmkp-bookmark))) + (prog1 bmk (when msgp (if bmk (bmkp-describe-bookmark bmk) (message "No bookmark here")))))) + + (defun bmkp-bookmark-linked-at-mouse (event) + "Return the bookmark linked at the mouse position." + (interactive "e") + (bmkp-bookmark-linked-at (posn-point (event-end event)) 'MSG)) + + (defun bmkp-jump-to-bookmark-linked-at (&optional position) + "Jump to the bookmark linked at POSITION (default: point). +If a bookmark is linked at POSITION then jump to it. Else raise an error." + (interactive "d") + (let ((bmk (bmkp-bookmark-linked-at position))) + (unless bmk (error "No bookmark here")) + (bookmark-jump-other-window bmk))) + + (defun bmkp-jump-to-bookmark-linked-at-mouse (event) + "Jump to the bookmark linked at the mouse position." + (interactive "e") + (bmkp-jump-to-bookmark-linked-at (posn-point (event-end event)))) + + (defun bmkp-insert-bookmark-link (bookmark text &optional position) + "Put a link to BOOKMARK on the active region or at point. +You are prompted for the bookmark name. +If the region is active and nonempty then put the link on its text. + +Otherwise, you are prompted for the link text, which is inserted at +point. The default text for this is the BOOKMARK name. An unlinked +`SPC' char is inserted after the link, unless it is at the end of a +line. + +Using `?' or double-clicking `mouse-1' on the link describes the +BOOKMARK. Using `RET' or `mouse-2' on it jumps to BOOKMARK in another +window. + +BOOKMARK is a bookmark name or a bookmark record. + +Non-interactively, if the region is inactive or empty then TEXT is the +link text, and it is inserted at POSITION (point if POSITION is nil)." + (interactive + (let* ((bmk (bookmark-completing-read "Bookmark")) + (txt (if (and transient-mark-mode mark-active (> (region-end) (region-beginning))) + (buffer-substring-no-properties (region-end) (region-beginning)) + (read-string "Insert text: " nil nil bmk)))) + (list bmk txt))) + (with-buffer-modified-unmodified + (let* ((regionp (and transient-mark-mode mark-active (> (region-end) (region-beginning)))) + (beg (if regionp (region-beginning) (or position (point)))) + (end (and regionp (region-end))) + (bmk (bmkp-get-bookmark bookmark)) + (map (make-sparse-keymap))) + (unless bmk (error "No such bookmark")) + ;; Use `copy-sequence'. The bookmark name in the bookmark might change. + (setq bookmark (copy-sequence (bmkp-bookmark-name-from-record bmk))) + (put-text-property 0 (length bookmark) 'bmkp-bookmark bmk bookmark) + (define-key map "?" 'bmkp-bookmark-linked-at) + (define-key map "\r" 'bmkp-jump-to-bookmark-linked-at) + (define-key map [double-mouse-1] 'bmkp-bookmark-linked-at-mouse) + (define-key map [mouse-2] 'bmkp-jump-to-bookmark-linked-at-mouse) + (define-key map [follow-link] 'mouse-face) + (unless regionp (insert text)) + (add-text-properties beg (or end (point)) + `(bmkp-bookmark ,bookmark + keymap ,map + font-lock-ignore t ; Prevent font-lock from changing the face. + face link + mouse-face highlight + help-echo + "RET, mouse-2: jump to bookmark; ?, double-mouse-1: describe bookmark")) + (unless (or regionp (eolp)) (insert " "))))) + + ) + + +;;(@* "Other Bookmark+ Functions (`bmkp-*')") +;; *** Other Bookmark+ Functions (`bmkp-*') *** + +;;;###autoload (autoload 'bmkp-describe-bookmark "bookmark+") +(defun bmkp-describe-bookmark (bookmark &optional defn) ; Bound to `C-h M' + "Describe BOOKMARK. +With a prefix argument, show the internal definition of the bookmark. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'. + +Starting with Emacs 22, if the file is an image file then: +* Show a thumbnail of the image as well. +* If you have command-line tool `exiftool' installed and in your + `$PATH' or `exec-path', then show EXIF data (metadata) about the + image. See standard Emacs library `image-dired.el' for more + information about `exiftool'" + (interactive (list (bookmark-completing-read "Describe bookmark" + (or (and (fboundp 'bmkp-default-lighted) + (bmkp-default-lighted)) + (bmkp-default-bookmark-name))) + current-prefix-arg)) + (if defn + (bmkp-describe-bookmark-internals bookmark) + (setq bookmark (bmkp-get-bookmark bookmark)) + (help-setup-xref (list #'bmkp-describe-bookmark bookmark) (interactive-p)) + (let ((help-text (bmkp-bookmark-description bookmark))) + (bmkp-with-help-window "*Help*" (princ help-text) (bmkp-add-jump-to-list-button bookmark)) + (with-current-buffer "*Help*" + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "@#%&()_IMAGE-HERE_()&%#@\\(.+\\)" nil t) + (let* ((image-file (match-string 1)) + (image-string (save-match-data + (apply #'propertize "X" + `(display + ,(append (image-dired-get-thumbnail-image image-file) + '(:margin 10)) + rear-nonsticky (display) + mouse-face highlight + follow-link t + help-echo "`mouse-2' or `RET': Show full image" + keymap + (keymap + (mouse-2 + . (lambda (e) (interactive "e") + (find-file ,image-file))) + (13 + . (lambda () (interactive) + (find-file ,image-file)))))))) + (buffer-read-only nil)) + (replace-match image-string))))) + help-text))) + +(defun bmkp-bookmark-description (bookmark &optional no-image) + "Help-text description of BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'. + +Starting with Emacs 22 and unless optional arg NO-IMAGE is non-nil, if +the file is an image file then the description includes the following: +* A placeholder for a thumbnail image: \"@#%&()_IMAGE-HERE_()&%#@\" +* EXIF data (metadata) about the image, provided you have command-line + tool `exiftool' installed and in your `$PATH' or `exec-path'. See + standard Emacs library `image-dired.el' for more information about + `exiftool'." + (setq bookmark (bmkp-get-bookmark bookmark)) + (let ((print-circle bmkp-propertize-bookmark-names-flag) ; For `pp-to-string' + (print-gensym bmkp-propertize-bookmark-names-flag) ; For `pp-to-string' + (print-length nil) ; For `pp-to-string' + (print-level nil) ; For `pp-to-string' + (bname (bmkp-bookmark-name-from-record bookmark)) + (buf (bmkp-get-buffer-name bookmark)) + (file (bookmark-get-filename bookmark)) + (image-p (bmkp-image-bookmark-p bookmark)) + (location (bookmark-prop-get bookmark 'location)) + (start (bookmark-get-position bookmark)) + (end (bmkp-get-end-position bookmark)) + (created (bookmark-prop-get bookmark 'created)) + (time (bmkp-get-visit-time bookmark)) + (visits (bmkp-get-visits-count bookmark)) + (tags (mapcar #'bmkp-tag-name (bmkp-get-tags bookmark))) + (sequence-p (bmkp-sequence-bookmark-p bookmark)) + (function-p (bmkp-function-bookmark-p bookmark)) + (kmacro-p (bmkp-kmacro-list-bookmark-p bookmark)) + (variable-list-p (bmkp-variable-list-bookmark-p bookmark)) + (search-hits-p (bmkp-icicles-search-hits-bookmark-p bookmark)) + (non-invokable-p (bmkp-non-invokable-bookmark-p bookmark)) + (desktop-p (bmkp-desktop-bookmark-p bookmark)) + (bookmark-file-p (bmkp-bookmark-file-bookmark-p bookmark)) + (snippet-p (bmkp-snippet-bookmark-p bookmark)) + (dired-p (bmkp-dired-bookmark-p bookmark)) + (gnus-p (bmkp-gnus-bookmark-p bookmark)) + (info-p (bmkp-info-bookmark-p bookmark)) + (man-p (bmkp-man-bookmark-p bookmark)) + (url-p (bmkp-url-bookmark-p bookmark)) + (eww-p (and (fboundp 'bmkp-eww-bookmark-p) (bmkp-eww-bookmark-p bookmark))) ; Emacs 25+ + (w3m-p (bmkp-w3m-bookmark-p bookmark)) + (temp-p (bmkp-temporary-bookmark-p bookmark)) + (annot (bookmark-get-annotation bookmark)) + non-file-p no-position-p) + (setq non-file-p (equal file bmkp-non-file-filename) + no-position-p (not start)) + (when (or sequence-p function-p variable-list-p kmacro-p search-hits-p) (setq no-position-p t)) + (let* ((temp-text (if temp-p "TEMPORARY " "")) + (help-text + (concat + (format "%sBookmark `%s'\n%s\n\n" temp-text bname + (make-string (+ 11 (length temp-text) (length bname)) ?-)) + (cond (sequence-p (concat "Sequence:\n\t" + (mapconcat (lambda (bname) + (let ((name (copy-sequence bname))) + (set-text-properties 0 (length name) () name) + name)) + (bookmark-prop-get bookmark 'sequence) + "\n\t") + "\n")) + (function-p (let ((fn (bookmark-prop-get bookmark 'function))) + (if (symbolp fn) + (format "Function:\t\t%s\n" fn) + (format "Function:\n%s\n" + (pp-to-string (bookmark-prop-get bookmark 'function)))))) + (kmacro-p (format "Keyboard Macro List (MACRO COUNT COUNT-FORMAT):\n\n%s\n" + (pp-to-string (bookmark-prop-get bookmark 'kmacros)))) + (variable-list-p (format "Variable list:\n%s\n" + (pp-to-string (bookmark-prop-get bookmark 'variables)))) + (search-hits-p (format "Icicles search hits:\n%s\n\n" + (mapconcat (lambda (hit) + (let ((hit-copy (copy-sequence hit))) + (set-text-properties 0 (length hit-copy) () + hit-copy) + hit-copy)) + (bookmark-prop-get bookmark 'hits) + "\n\t"))) + (non-invokable-p (format "Non-invokable:\n\n%s" + (let ((desc (bookmark-prop-get bookmark 'filter-description))) + (if desc + (format "Isearch filter:\n%s\n" desc) + "")))) + (gnus-p (format "Gnus, group:\t\t%s, article: %s, message-id: %s\n" + (bookmark-prop-get bookmark 'group) + (bookmark-prop-get bookmark 'article) + (bookmark-prop-get bookmark 'message-id))) + (man-p (format "UNIX `man' page for:\t`%s'\n" + (or (bookmark-prop-get bookmark 'man-args) + ;; WoMan has no variable for the cmd name. + (bookmark-prop-get bookmark 'buffer-name)))) + (info-p (and file (format "Info node:\t\t(%s) %s\n" + (file-name-nondirectory file) + (bookmark-prop-get bookmark 'info-node)))) + (eww-p (and file (format "EWW URL:\t\t%s\n" file))) ; Emacs 25+ + (w3m-p (and file (format "W3m URL:\t\t%s\n" file))) + (url-p (format "URL:\t\t\t%s\n" location)) + (desktop-p (format "Desktop file:\t\t%s\n" + (bookmark-prop-get bookmark 'desktop-file))) + (bookmark-file-p (format "Bookmark file:\t\t%s\n" + (bookmark-prop-get bookmark 'bookmark-file))) + (snippet-p (format "Snippet for `kill-ring'.\n")) + (dired-p (and file + (let ((switches (bookmark-prop-get bookmark 'dired-switches)) + (marked (length (bookmark-prop-get bookmark + 'dired-marked))) + (inserted (length (bookmark-prop-get bookmark + 'dired-subdirs))) + (hidden (length (bookmark-prop-get bookmark + 'dired-hidden-dirs)))) + (format "Dired%s:%s\t\t%s\nMarked:\t\t\t%s\n\ +Inserted subdirs:\t%s\nHidden subdirs:\t\t%s\n" + (if switches (format " `%s'" switches) "") + (if switches "" (format "\t")) + (expand-file-name file) + marked inserted hidden)))) + (non-file-p (or (and location (format "Location:\t\t%s\n" location)) + (and buf (format "Buffer:\t\t\t%s\n" buf)))) + (file (concat (format "File:\t\t\t%s\n" (file-name-nondirectory file)) + (let ((dir (file-name-directory (expand-file-name file)))) + (and dir (format "Directory:\t\t%s\n" dir))))) + (t "Unknown\n")) + (unless no-position-p + (if (bmkp-region-bookmark-p bookmark) + (format "Region:\t\t\t%d to %d (%d chars)\n" start end (- end start)) + (format "Position:\t\t%d\n" start))) + (and visits (format "Visits:\t\t\t%d\n" visits)) + (and time (format "Last visit:\t\t%s\n" (format-time-string "%c" time))) + (and created (format "Creation:\t\t%s\n" (format-time-string "%c" created))) + (and tags (format "Tags:\n \"%s\"\n" (mapconcat #'identity tags "\"\n \""))) + (and annot (format "\nAnnotation:\n%s\n" annot)) + (and snippet-p (format "\nSnippet:\n%s\n" (bookmark-prop-get bookmark 'text))) + (and (not no-image) + file + (fboundp 'image-file-name-regexp) ; In `image-file.el' (Emacs 22+). + (bmkp-string-match-p (image-file-name-regexp) file) + (if (fboundp 'display-graphic-p) (display-graphic-p) window-system) + (require 'image-dired nil t) + (image-dired-get-thumbnail-image file) + (concat "\n@#%&()_IMAGE-HERE_()&%#@" file "\n")) + (and (not no-image) + file + (fboundp 'image-file-name-regexp) ; In `image-file.el' (Emacs 22+). + (bmkp-string-match-p (image-file-name-regexp) file) + (progn (message "Gathering image data...") t) + (condition-case nil + (let ((all (bmkp-all-exif-data (expand-file-name file)))) + (concat + (and all (not (zerop (length all))) + (format "\nImage Data (EXIF)\n-----------------\n%s" + all)))) + (error nil)))))) + help-text))) + +(when (and (> emacs-major-version 21) + (condition-case nil (require 'help-mode nil t) (error nil)) + (get 'help-xref 'button-category-symbol)) ; In `button.el' + (define-button-type 'bmkp-jump-to-list-button + :supertype 'help-xref + 'help-function #'bmkp-jump-to-list + 'help-echo + (purecopy "mouse-2, RET: Show in `*Bookmark List*'"))) + +(defun bmkp-add-jump-to-list-button (bookmark) + "Add a [Show in `*Bookmark List*'] button for BOOKMARK." + (with-current-buffer "*Help*" + (let ((buffer-read-only nil)) + ;; Add button to go to the bookmark entry in `*Bookmark List*'. + ;; Not for Emacs 21.3 - its `help-insert-xref-button' signature is different. + (when (and (> emacs-major-version 21) ; In `help-mode.el'. + (condition-case nil (require 'help-mode nil t) (error nil)) + (fboundp 'help-insert-xref-button)) + (goto-char (point-min)) (forward-line 2) + (help-insert-xref-button "[Show in `*Bookmark List*']" + #'bmkp-jump-to-list-button + (bookmark-name-from-record bookmark)) + (insert "\n"))))) + +;; This is the same as `help-all-exif-data' in `help-fns+.el', but we avoid requiring that library. +(defun bmkp-all-exif-data (file) + "Return all EXIF data from FILE, using command-line tool `exiftool'." + (with-temp-buffer + (delete-region (point-min) (point-max)) + (unless (eq 0 (call-process shell-file-name nil t nil shell-command-switch + (format "exiftool -All \"%s\"" file))) + (error "Could not get EXIF data")) + (buffer-string))) + + +;;;###autoload (autoload 'bmkp-describe-bookmark-internals "bookmark+") +(defun bmkp-describe-bookmark-internals (bookmark) + "Show the internal definition of the bookmark BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +If it is a record then it need not belong to `bookmark-alist'." + (interactive (list (bookmark-completing-read "Describe bookmark" (bmkp-default-bookmark-name)))) + ;; Work with a copy of the bookmark, so we can unpropertize the name. + (setq bookmark (copy-sequence (bmkp-get-bookmark bookmark))) + (help-setup-xref (list #'bmkp-describe-bookmark-internals bookmark) (interactive-p)) + (let* ((bname (copy-sequence (bmkp-bookmark-name-from-record bookmark))) + (IGNORE (set-text-properties 0 (length bname) nil bname)) ; Strip properties from name. + (bmk (cons bname (bmkp-bookmark-data-from-record bookmark))) ; Fake bmk with stripped name. + (print-circle bmkp-propertize-bookmark-names-flag) ; For `pp-to-string' + (print-gensym bmkp-propertize-bookmark-names-flag) ; For `pp-to-string' + (print-length nil) ; For `pp-to-string' + (print-level nil) ; For `pp-to-string' + (help-text (format "Bookmark `%s'\n%s\n\n%s" bname (make-string (+ 11 (length bname)) ?-) + (pp-to-string bmk)))) + (bmkp-with-help-window "*Help*" (princ help-text)) + (bmkp-add-jump-to-list-button bookmark) + help-text)) + +(defun bmkp-annotation-or-bookmark-description (bookmark) + "Return the annotation or description of BOOKMARK as a string. +If BOOKMARK has an annotation then use that; else the description." + (or (bookmark-get-annotation bookmark) + (bmkp-bookmark-description bookmark))) + +;;;###autoload (autoload 'bmkp-list-defuns-in-commands-file "bookmark+") +(defun bmkp-list-defuns-in-commands-file () + "List the functions defined in `bmkp-bmenu-commands-file'. +Typically, these are all commands." + (interactive) + (when (and bmkp-bmenu-commands-file (file-readable-p bmkp-bmenu-commands-file)) + (when (file-directory-p bmkp-bmenu-commands-file) + (error "`%s' is a directory, not a file" bmkp-bmenu-commands-file)) + (let ((fns ()) + (buf (let ((enable-local-variables nil)) + (find-file-noselect bmkp-bmenu-commands-file)))) + (help-setup-xref (list #'bmkp-list-defuns-in-commands-file) (interactive-p)) + (with-current-buffer buf + (goto-char (point-min)) + (while (not (eobp)) + (when (re-search-forward "\\s-*(defun \\([^ \t\n(\"]+\\)[ \t\n(]" nil 'move) + (push (match-string 1) fns))) + (setq fns (nreverse fns) + fns (sort fns 'string-lessp))) + (when (buffer-live-p buf) (kill-buffer buf)) + (bmkp-with-help-window "*Help*" + (princ "Bookmark Commands You Defined (in `bmkp-bmenu-commands-file')") (terpri) + (princ "------------------------------------------------------------------") (terpri) + (terpri) + (let ((non-dups (bmkp-remove-dups fns))) + (dolist (fn non-dups) + (if (and (fboundp (intern fn)) (fboundp 'help-insert-xref-button)) + (with-current-buffer "*Help*" + (goto-char (point-max)) + (help-insert-xref-button fn 'help-function (intern fn) (commandp (intern fn)))) + (princ fn)) + (let ((dups (member fn fns)) ; Sorted, so all dups are together. + (count 0)) + (while (equal fn (car dups)) + (setq count (1+ count) + dups (cdr dups))) + (when (> count 1) (princ (format " (%d times)" count)))) + (terpri))) + (help-make-xrefs (current-buffer))) + fns))) + +(defun bmkp-root-or-sudo-logged-p () + "Return t if the user logged in using Tramp as `root' or `sudo'. +Otherwise, return nil." + (catch 'break + (dolist (ii (mapcar #'buffer-name (buffer-list))) + (when (bmkp-string-match-p "*tramp/\\(su\\|sudo\\) ." ii) (throw 'break t))))) + +(defun bmkp-position-post-context (breg) + "Return `bookmark-search-size' chars, starting at position BREG. +Return nil if there are not that many chars. +This is text that follows the bookmark's `position'. +This is used for a non-region bookmark." + (and (>= (- (point-max) breg) bookmark-search-size) + (buffer-substring-no-properties breg (+ breg bookmark-search-size)))) + +(defun bmkp-position-post-context-region (breg ereg) + "Return the region prefix, at BREG. +Return at most `bmkp-region-search-size' or (- EREG BREG) chars. +This is text that follows the bookmark's `position'. +This is used for a region bookmark." + (buffer-substring-no-properties breg (+ breg (min bmkp-region-search-size (- ereg breg))))) + +(defun bmkp-position-pre-context (breg) + "Return `bookmark-search-size' chars that precede BREG. +Return nil if there are not that many chars. +This is text that precedes the bookmark's `position'. +This is used for a non-region bookmark." + (and (>= (- breg (point-min)) bookmark-search-size) + (buffer-substring-no-properties breg (- breg bookmark-search-size)))) + +(defun bmkp-position-pre-context-region (breg) + "Return the text preceding the region beginning, BREG. +Return at most `bmkp-region-search-size' chars. +This is text that precedes the bookmark's `position'. +This is used for a region bookmark." + (buffer-substring-no-properties (max (- breg bmkp-region-search-size) (point-min)) breg)) + +(defun bmkp-end-position-pre-context (breg ereg) + "Return the region suffix, ending at EREG. +Return at most `bmkp-region-search-size' or (- EREG BREG) chars. +This is text that precedes the bookmark's `end-position'." + (buffer-substring-no-properties (- ereg (min bmkp-region-search-size (- ereg breg))) ereg)) + +(defun bmkp-end-position-post-context (ereg) + "Return the text following the region end, EREG. +Return at most `bmkp-region-search-size' chars. +This is text that follows the bookmark's `end-position'." + (buffer-substring-no-properties ereg (+ ereg (min bmkp-region-search-size (- (point-max) ereg))))) + +(defun bmkp-position-after-whitespace (position) + "Move forward from POSITION, skipping over whitespace. Return point." + (goto-char position) (skip-chars-forward " \n\t" (point-max)) (point)) + +(defun bmkp-position-before-whitespace (position) + "Move backward from POSITION, skipping over whitespace. Return point." + (goto-char position) (skip-chars-backward " \n\t" (point-min)) (point)) + +(defun bmkp-save-new-region-location (bookmark beg end) + "Update and save `bookmark-alist' for BOOKMARK, relocating its region. +Saving happens according to `bookmark-save-flag'. +BOOKMARK is a bookmark record. +BEG and END are the new region limits for BOOKMARK. +Do nothing and return nil if `bmkp-save-new-location-flag' is nil. +Otherwise, return non-nil if region was relocated." + (and bmkp-save-new-location-flag + (y-or-n-p "Region relocated. Do you want to save new region limits? ") + (progn + (bookmark-prop-set bookmark 'front-context-string (bmkp-position-post-context-region beg end)) + (bookmark-prop-set bookmark 'rear-context-string (bmkp-position-pre-context-region beg)) + (bookmark-prop-set bookmark 'front-context-region-string (bmkp-end-position-pre-context beg end)) + (bookmark-prop-set bookmark 'rear-context-region-string (bmkp-end-position-post-context end)) + (bookmark-prop-set bookmark 'position beg) + (bookmark-prop-set bookmark 'end-position end) + (bmkp-maybe-save-bookmarks) + t))) + +(defun bmkp-handle-region-default (bookmark) + "Default function to handle BOOKMARK's region. +BOOKMARK is a bookmark name or a bookmark record. +Relocate the region if necessary, then activate it. +If region was relocated, save it if user confirms saving." + ;; Relocate by searching from the beginning (and possibly the end) of the buffer. + (let* (;; Get bookmark object once and for all. + ;; We should know BOOKMARK is a bookmark record (not a name), but play it safe. + (bmk (bmkp-get-bookmark bookmark)) + (bor-str (bookmark-get-front-context-string bmk)) + (eor-str (bookmark-prop-get bmk 'front-context-region-string)) + (br-str (bookmark-get-rear-context-string bmk)) + (ar-str (bookmark-prop-get bookmark 'rear-context-region-string)) + (pos (bookmark-get-position bmk)) + (end-pos (bmkp-get-end-position bmk)) + (reg-retrieved-p t) + (reg-relocated-p nil)) + (unless (and end-pos + (string= bor-str (buffer-substring-no-properties + (point) (min (point-max) (+ (point) (length bor-str))))) + (string= eor-str (buffer-substring-no-properties + end-pos (max (point-min) (- end-pos (length bor-str)))))) + ;; Relocate region by searching from beginning (and possibly from end) of buffer. + (let ((beg nil) + (end nil)) + ;; Go to bob and search forward for END. + (goto-char (point-min)) + (if (search-forward eor-str (point-max) t) ; Find END, using `eor-str'. + (setq end (point)) + ;; Verify that region is not before context. + (unless (search-forward br-str (point-max) t) + (when (search-forward ar-str (point-max) t) ; Find END, using `ar-str'. + (setq end (match-beginning 0) + end (and end (bmkp-position-before-whitespace end)))))) + ;; If failed to find END, go to eob and search backward for BEG. + (unless end (goto-char (point-max))) + (if (search-backward bor-str (point-min) t) ; Find BEG, using `bor-str'. + (setq beg (point)) + ;; Verify that region is not after context. + (unless (search-backward ar-str (point-min) t) + (when (search-backward br-str (point-min) t) ; Find BEG, using `br-str'. + (setq beg (match-end 0) + beg (and beg (bmkp-position-after-whitespace beg)))))) + (setq reg-retrieved-p (or beg end) + reg-relocated-p reg-retrieved-p + ;; If only one of BEG or END was found, the relocated region is only + ;; approximate (keep the same length). If both were found, it is exact. + pos (or beg (and end pos end-pos (- end (- end-pos pos))) pos) + end-pos (or end (and beg pos end-pos (+ pos (- end-pos pos))) end-pos)))) + ;; Region is available. Activate it and maybe save it. + (cond (reg-retrieved-p + (when pos (goto-char pos)) + (when end-pos (push-mark end-pos 'nomsg 'activate)) + (when bmkp-show-end-of-region-flag + (let ((end-win (save-excursion (forward-line (window-height)) (line-end-position)))) + ;; Bounce point and mark. + (save-excursion (sit-for 0.6) (exchange-point-and-mark) (sit-for 1)) + ;; Recenter if region end is not visible. + (when (and end-pos (> end-pos end-win)) (recenter 1)))) + ;; Maybe save region. + (if (and reg-relocated-p (bmkp-save-new-region-location bmk pos end-pos)) + (message "Saved relocated region%s" (if (and pos end-pos) + (format " (from %d to %d)" pos end-pos) + "")) + (when (and pos end-pos) (message "Region is from %d to %d" pos end-pos))) + (when (and pos end-pos) + (goto-char pos) + (push-mark end-pos 'nomsg 'activate) + (setq deactivate-mark nil))) + ((and pos end-pos) ; No region. Go to old start. Don't push-mark. + (goto-char pos) (forward-line 0) + (message "No region from %d to %d" pos end-pos))))) + +(defun bmkp-goto-position (bookmark file buf bufname pos forward-str behind-str) + "Go to a bookmark that has no region. +Update the recorded position if POS and `bmkp-save-new-location-flag' +are non-nil. + +Arguments are respectively the bookmark, its file, buffer, buffer +name, recorded position, and the context strings for the position." + (if (and file (file-readable-p file) (not (buffer-live-p buf))) +;;; $$$$$$$ (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (with-current-buffer (find-file-noselect file) (setq buf (buffer-name))) + ;; No file found. See if a non-file buffer exists for this. If not, raise error. + (unless (or (and buf (get-buffer buf)) + (and bufname (get-buffer bufname) (not (string= buf bufname)))) + (signal 'file-error `("Jumping to bookmark" ,(format "Cannot access file `%s' or buffer `%s'" + file bufname))))) + (set-buffer (or buf bufname)) + (when bmkp-jump-display-function + (save-current-buffer (funcall bmkp-jump-display-function (current-buffer)))) + (setq deactivate-mark t) + (raise-frame) + (when pos (goto-char pos)) + ;; Try to relocate position. + ;; Search forward first. Then, if FORWARD-STR exists and was found in the file, search + ;; backward for BEHIND-STR. The rationale is that if text was inserted between the two + ;; in the file, then it's better to end up before point, so you can see the text, rather + ;; than after it and not see it. + (when (and forward-str (search-forward forward-str (point-max) t)) + (goto-char (match-beginning 0))) + (when (and behind-str (search-backward behind-str (point-min) t)) (goto-char (match-end 0))) + (when (and (not (equal pos (point))) bmkp-save-new-location-flag) + (bookmark-prop-set bookmark 'position (point)) + (bookmark-prop-set bookmark 'end-position (point)) + ;; Perhaps we should treat the case of a bookmark that had position 0 changing to position 1 specially, + ;; by passing non-nil SAME-COUNT-P arg to `bmkp-maybe-save-bookmarks'. On the other hand, if initially + ;; 0 then the bookmark does not claim that the file is non-empty. If now set to 1 then we know it is. + ;; Leave it this way, at least for now. The consequence is that the user will see that bookmarks have + ;; modified (e.g. `Save' is enabled in the menu), even though nothing much has changed. + (bmkp-maybe-save-bookmarks)) + (not (equal pos (point)))) ; Return value indicates whether POS was accurate. + +(defun bmkp-jump-sequence (bookmark) + "Handle a sequence bookmark BOOKMARK. +Handler function for sequence bookmarks. +BOOKMARK is a bookmark name or a bookmark record." + (dolist (bmk (bookmark-prop-get bookmark 'sequence)) + (bookmark--jump-via bmk bmkp-sequence-jump-display-function)) + (message "Done invoking bookmarks in sequence `%s'" + (if (stringp bookmark) bookmark (bmkp-bookmark-name-from-record bookmark)))) + +(defun bmkp-jump-function (bookmark) + "Handle a function bookmark BOOKMARK. +Handler function for function bookmarks. +BOOKMARK is a bookmark name or a bookmark record." + (let ((fn (bookmark-prop-get bookmark 'function))) + (cond ((functionp fn) (funcall fn)) + ((vectorp fn) + (execute-kbd-macro fn current-prefix-arg))))) + +(defun bmkp-make-bookmark-list-record () + "Create and return a bookmark-list bookmark record. +This records the current state of buffer `*Bookmark List*': the sort +order, filter function, regexp pattern, title, and omit list." + (let ((state `((last-sort-comparer . ,bmkp-sort-comparer) + (last-reverse-sort-p . ,bmkp-reverse-sort-p) + (last-reverse-multi-sort-p . ,bmkp-reverse-multi-sort-p) + (last-bmenu-filter-function . ,bmkp-bmenu-filter-function) + (last-bmenu-filter-pattern . ,bmkp-bmenu-filter-pattern) + (last-bmenu-omitted-bookmarks . ,(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-omitted-bookmarks)) + (last-bmenu-title . ,bmkp-bmenu-title) + (last-bmenu-toggle-filenames . ,bookmark-bmenu-toggle-filenames)))) + `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT) + (filename . ,bmkp-non-file-filename) + (bookmark-list . ,state) + (handler . bmkp-jump-bookmark-list)))) + +(add-hook 'bookmark-bmenu-mode-hook + (lambda () (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-bookmark-list-record))) + +(defun bmkp-jump-bookmark-list (bookmark) + "Jump to bookmark-list bookmark BOOKMARK. +Handler function for record returned by +`bmkp-make-bookmark-list-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let ((state (bookmark-prop-get bookmark 'bookmark-list))) + (setq bmkp-sort-comparer (cdr (assq 'last-sort-comparer state)) + bmkp-reverse-sort-p (cdr (assq 'last-reverse-sort-p state)) + bmkp-reverse-multi-sort-p (cdr (assq 'last-reverse-multi-sort-p state)) + bmkp-bmenu-filter-function (cdr (assq 'last-bmenu-filter-function state)) + bmkp-bmenu-filter-pattern (or (cdr (assq 'last-bmenu-filter-pattern state)) "") + bmkp-bmenu-omitted-bookmarks (cdr (assq 'last-bmenu-omitted-bookmarks state)) + bmkp-bmenu-title (cdr (assq 'last-bmenu-title state)) + bookmark-bmenu-toggle-filenames (cdr (assq 'last-bmenu-toggle-filenames state)))) + (let ((bookmark-alist (if bmkp-bmenu-filter-function + (funcall bmkp-bmenu-filter-function) + bookmark-alist))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp) + (when (get-buffer bmkp-bmenu-buffer) (pop-to-buffer bmkp-bmenu-buffer)))) + +;; Bookmark-file bookmarks. +;;;###autoload (autoload 'bmkp-set-bookmark-file-bookmark "bookmark+") +(defun bmkp-set-bookmark-file-bookmark (file &optional msg-p) ; Bound to `C-x x y', `C-x x c y' + "Create a bookmark that loads bookmark-file FILE when \"jumped\" to. +You are prompted for the names of the bookmark file and the bookmark. +When entering the bookmark name you can use completion against +existing names. This completion is lax, so you can easily edit an +existing name. See `bookmark-set' for particular keys available +during this input. + +Non-interactively, non-nil MSG-P means display a status message." + (interactive + (list (let* ((insert-default-directory t) + (std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + bookmark-default-file + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Create bookmark to load bookmark file: " + (or (file-name-directory default) "~/") + default + 'confirm)) ; Non-existing file is OK, but must confirm. + 'MSG)) + (setq file (expand-file-name file)) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (unless (file-readable-p file) (error "Unreadable bookmark file `%s'" file)) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) + (condition-case nil ; Check whether it's a valid bookmark file. + (progn (bookmark-maybe-upgrade-file-format) + (unless (listp (bookmark-alist-from-buffer)) (error ""))) + (error (error "Not a valid bookmark file: `%s'" file)))) + (let ((bookmark-make-record-function (lexical-let ((ff file)) + (lambda () (bmkp-make-bookmark-file-record ff)))) + (bookmark-name (bmkp-completing-read-lax "Bookmark-file BOOKMARK name" + file nil nil 'bookmark-history))) + (bookmark-set bookmark-name 99 'INTERACTIVEP)) + (when msg-p (message "Set bookmark-file bookmark"))) + +(defun bmkp-make-bookmark-file-record (bookmark-file) + "Create and return a bookmark-file bookmark record. +Records the BOOKMARK-FILE name. +Adds a handler that tests the prefix arg and loads the bookmark file +either as a replacement for the current bookmark file or as a +supplement to it." + `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT nil nil 'NO-REGION) + (filename . ,bookmark-file) + (bookmark-file . ,bookmark-file) + (handler . bmkp-jump-bookmark-file))) + +(defun bmkp-jump-bookmark-file (bookmark &optional switchp batchp) + "Jump to bookmark-file bookmark BOOKMARK, which loads the bookmark file. +Handler function for record returned by +`bmkp-make-bookmark-file-record'. +BOOKMARK is a bookmark name or a bookmark record. +Non-nil optional arg SWITCHP means overwrite current bookmark list. +Non-nil optional arg BATCHP is passed to `bookmark-load'." + (let ((file (bookmark-prop-get bookmark 'bookmark-file)) + (overwritep (and switchp (y-or-n-p "SWITCH to new bookmark file, instead of just adding it? ")))) + (bookmark-load file overwritep batchp)) ; Treat load interactively, if no BATCHP. + ;; This `throw' is only for the case where this handler is called from `bookmark--jump-via'. + ;; It just tells `bookmark--jump-via' to skip the rest of what it does after calling the handler. + (condition-case nil + (throw 'bookmark--jump-via 'BOOKMARK-FILE-JUMP) + (no-catch nil))) + +;;;###autoload (autoload 'bmkp-bookmark-file-jump "bookmark+") +(defun bmkp-bookmark-file-jump (bookmark &optional switchp no-msg) ; `C-x j y' + "Jump to a bookmark-file bookmark, which means load its bookmark file. +With a prefix argument, switch to the new bookmark file. +Otherwise, load it to supplement the current bookmark list. +BOOKMARK is a bookmark name or a bookmark record." + (interactive + (let ((alist (bmkp-bookmark-file-alist-only))) + (list (bmkp-read-bookmark-for-type "bookmark-file" alist nil nil 'bmkp-bookmark-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-bookmark-file-alist-only)))) + (bmkp-jump-bookmark-file bookmark switchp no-msg)) + +;;;###autoload (autoload 'bmkp-bookmark-file-load-jump "bookmark+") +(defun bmkp-bookmark-file-load-jump (bookmark &optional nosavep) + "Prompt for a bookmark-file BOOKMARK and load that file's bookmarks. +This adds to the current bookmark list. It does not overwrite it. +By default, this first saves the current bookmark list in the current +bookmark file. With a prefix argument it does not save first. +BOOKMARK is a bookmark name or a bookmark record." + (interactive + (let ((alist (bmkp-bookmark-file-alist-only))) + (list (bmkp-read-bookmark-for-type "bookmark-file" alist nil nil 'bmkp-bookmark-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-bookmark-file-alist-only)))) + (let ((file (bookmark-prop-get bookmark 'bookmark-file))) + (bookmark-load file nil (if nosavep t 'save)) + (bmkp-refresh/rebuild-menu-list) + (message "Added bookmarks in `%s'" file))) + +;;;###autoload (autoload 'bmkp-bookmark-file-switch-jump "bookmark+") +(defun bmkp-bookmark-file-switch-jump (bookmark &optional nosavep) + "Prompt for a bookmark-file BOOKMARK and switch to that bookmark file. +Unlike `C-u \\[bmkp-bookmark-file-jump]', you are not prompted for confirmation. +By default, this first saves the current bookmark list in the current +bookmark file. With a prefix argument it does not save first. +BOOKMARK is a bookmark name or a bookmark record." + (interactive + (let ((alist (bmkp-bookmark-file-alist-only))) + (list (bmkp-read-bookmark-for-type "bookmark-file" alist nil nil 'bmkp-bookmark-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-bookmark-file-alist-only)))) + (let ((file (bookmark-prop-get bookmark 'bookmark-file))) + (bookmark-load file t (if nosavep t 'save)) + (bmkp-refresh/rebuild-menu-list) + (message "Switched to bookmarks in `%s'" file))) + + +;; Snippet bookmarks +;; Inspired by emacs-devel@gnu.org post from Masatake Yamato [yamato@redhat.com], 2012-01-06. +;;;###autoload (autoload 'bmkp-set-snippet-bookmark "bookmark+") +(defun bmkp-set-snippet-bookmark (beg end &optional promptp msgp) + ; Bound globally to `C-x x c M-w'. + "Save the text of the active region as a bookmark. +The bookmark is automatically named with the first line of the region +text. With a prefix argument you are prompted for the name instead. + +Jumping to the bookmark copies the saved text to the `kill-ring', so +you can yank it using `C-y'." + (interactive "r\nP\np") + (unless (and mark-active transient-mark-mode) (error "No active region")) + (when (equal beg end) (error "Region is empty")) + (lexical-let ((text (buffer-substring-no-properties beg end))) + (let ((bookmark-make-record-function (lambda () + `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT) + (text . ,text) + (handler . bmkp-jump-snippet)))) + (bname (and (not promptp) (car (split-string text "[\n]"))))) + (bookmark-set bname 99 'INTERACTIVEP) + ;; `bookmark-set does the prompting, providing default names. + (when msgp (message "Region text bookmarked%s" (if bname (format " as `%s'" bname) "")))))) + +(defun bmkp-jump-snippet (bookmark) + "Copy the text saved in BOOKMARK to the `kill-ring'. +Handler for snippet bookmarks." + (kill-new (bookmark-prop-get bookmark 'text)) + (message "Snippet of bookmark `%s' copied to `kill-ring'" (bmkp-bookmark-name-from-record bookmark))) + +;;;###autoload (autoload 'bmkp-snippet-to-kill-ring "bookmark+") +(defun bmkp-snippet-to-kill-ring (bookmark) ; `C-x j M-w' + "Jump to a snippet bookmark: copy its saved text to the `kill-ring'. +This is a specialization of `bookmark-jump' for snippet bookmarks." + (interactive + (let ((alist (bmkp-snippet-alist-only))) + (list (bmkp-read-bookmark-for-type "snippet" alist nil nil 'bmkp-snippet-history nil + "Copy snippet to kill ring")))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-snippet-alist-only)))) + (bmkp-jump-1 bookmark 'ignore)) + +;; Desktop bookmarks +;;;###autoload (autoload 'bmkp-set-desktop-bookmark "bookmark+") +(defun bmkp-set-desktop-bookmark (desktop-file &optional nosavep) + ; Bound globally to `C-x x K', `C-x r K', `C-x x c K' + "Save the desktop as a bookmark. +You are prompted for the desktop-file location and the bookmark name. +The default value for the desktop-file location is the current value +of `desktop-base-file-name'. As always, you can use `M-n' to retrieve +the default value. + +With a prefix arg, set a bookmark to an existing desktop file - do not +save the current desktop. Do not overwrite the file whose name you +enter, just use it to set the bookmark. + +If you also use library Icicles, then the desktop files of all +existing desktop bookmarks are available during the desktop file-name +completion as proxy candidates. To see them, use `C-M-_' to turn on +the display of proxy candidates." + (interactive + (progn (unless (condition-case nil (require 'desktop nil t) (error nil)) + (error "You must have library `desktop.el' to use this command")) + (let ((icicle-proxy-candidates (and (boundp 'icicle-mode) icicle-mode + (mapcar (lambda (bmk) + (bookmark-prop-get + bmk 'desktop-file)) + (bmkp-desktop-alist-only)))) + (icicle-unpropertize-completion-result-flag t)) + (list (read-file-name + (if current-prefix-arg "Use existing desktop file: " "Save desktop in file: ") + bmkp-desktop-default-directory + (if (boundp 'desktop-base-file-name) desktop-base-file-name desktop-basefilename) + current-prefix-arg) + current-prefix-arg)))) + (unless (or nosavep (condition-case nil (require 'desktop nil t) (error nil))) + (error "You must have library `desktop.el' to use this command")) + (unless (file-name-absolute-p desktop-file) + (setq desktop-file (expand-file-name desktop-file bmkp-desktop-default-directory))) + (set-text-properties 0 (length desktop-file) nil desktop-file) + (if nosavep + (unless (bmkp-desktop-file-p desktop-file) (error "Not a desktop file: `%s'" desktop-file)) + (bmkp-desktop-save desktop-file)) + (let ((bookmark-make-record-function (lexical-let ((df desktop-file)) + (lambda () (bmkp-make-desktop-record df)))) + (current-prefix-arg 99)) ; Use all bookmarks for completion, for `bookmark-set'. + (call-interactively #'bookmark-set))) + +(defun bmkp-desktop-save (desktop-file) + "Save current desktop in DESKTOP-FILE." + (let ((desktop-basefilename (file-name-nondirectory desktop-file)) ; Emacs < 22 + (desktop-base-file-name (file-name-nondirectory desktop-file)) ; Emacs 23+ + (desktop-dir (file-name-directory desktop-file)) + (desktop-restore-eager t) ; Don't bother with lazy restore. + (desktop-globals-to-save (bmkp-remove-if (lambda (elt) (memq elt bmkp-desktop-no-save-vars)) + desktop-globals-to-save))) + (cond ((< emacs-major-version 22) ; Emacs 22 introduced `RELEASE' (locking). + (desktop-save desktop-dir)) + ((or (< emacs-major-version 24) (and (= emacs-major-version 24) (< emacs-minor-version 4))) + (desktop-save desktop-dir 'RELEASE)) + (t ; Emacs 24.4 introduced `AUTOSAVE'. + (desktop-save desktop-dir 'RELEASE 'AUTOSAVE))) + (message "Desktop saved in `%s'" desktop-file))) + +(unless (fboundp 'desktop-full-file-name) ; Emacs < 22. (This is the vanilla definition.) + (defun desktop-full-file-name (&optional dirname) + "Return the full name of the desktop file in DIRNAME. +DIRNAME omitted or nil means use `desktop-dirname'." + (expand-file-name desktop-basefilename (or dirname desktop-dirname)))) + +(defun bmkp-desktop-save-as-last () + "Save desktop to the file that is the value of `bmkp-desktop-current-file'. +Do nothing if any of these are true: + + * `desktop-save-mode' is non-nil + * `bmkp-desktop-current-file' is nil + * `bmkp-desktop-current-file' does not seem to be current (a non-bookmark + desktop was last made current) + +You might want to use this on `kill-emacs-hook'." + (when (and (not desktop-save-mode) bmkp-desktop-current-file + (bmkp-same-file-p (desktop-full-file-name) bmkp-desktop-current-file)) + (bmkp-desktop-save bmkp-desktop-current-file))) + +;;; (defun bmkp-desktop-file-p (file) +;;; "Return non-nil if FILE is readable and appears to be a desktop file. +;;; FILE is a file-name string." +;;; (and (stringp file) +;;; (file-readable-p file) +;;; (with-current-buffer (let ((enable-local-variables nil)) (find-file-noselect file)) +;;; (goto-char (point-min)) +;;; (and (zerop (forward-line 2)) +;;; (bmkp-looking-at-p "^;; Desktop File for Emacs$"))))) + +;; Similar to `icicle-file-desktop-p' in `icicles-fn.el'. +;; This is better than using `find-file-noselect', which visits the file and leaves its buffer. +(defun bmkp-desktop-file-p (filename) + "Return non-nil if FILENAME names a desktop file." + (when (consp filename) (setq filename (car filename))) + (and (stringp filename) + (file-readable-p filename) + (not (file-directory-p filename)) + (with-temp-buffer + (insert-file-contents-literally filename nil 0 1000) + (goto-char (point-min)) + (and (zerop (forward-line 2)) + (bmkp-looking-at-p "^;; Desktop File for Emacs"))))) ; No $, because maybe eol chars (e.g. ^M). + +(defun bmkp-make-desktop-record (desktop-file) + "Create and return a desktop bookmark record. +DESKTOP-FILE is the absolute file name of the desktop file to use." + `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT nil nil 'NO-REGION) + (filename . ,bmkp-non-file-filename) + (desktop-file . ,desktop-file) + (handler . bmkp-jump-desktop))) + +(defun bmkp-jump-desktop (bookmark) + "Jump to desktop bookmark BOOKMARK. +Handler function for record returned by `bmkp-make-desktop-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let ((desktop-file (bookmark-prop-get bookmark 'desktop-file))) + (unless (condition-case nil (require 'desktop nil t) (error nil)) + (error "You must have library `desktop.el' to use this command")) + ;; (unless desktop-file (error "Not a desktop-bookmark: %S" bookmark)) ; Shouldn't happen. + (bmkp-desktop-change-dir desktop-file) + (unless (bmkp-desktop-read desktop-file) (error "Could not load desktop file")))) + +;; Derived from code in `desktop-change-dir'. +;;;###autoload (autoload 'bmkp-desktop-change-dir "bookmark+") +(defun bmkp-desktop-change-dir (desktop-file) + "Change to desktop saved in DESKTOP-FILE. +Kill the desktop as specified by variables `desktop-save-mode' and + `desktop-save' (starting with Emacs 22). +Clear the desktop and load DESKTOP-FILE." + (interactive + (progn (unless (condition-case nil (require 'desktop nil t) (error nil)) + (error "You must have library `desktop.el' to use this command")) + (list (let ((icicle-unpropertize-completion-result-flag t)) + (read-file-name "Change to desktop file: " bmkp-desktop-default-directory))))) + (unless (condition-case nil (require 'desktop nil t) (error nil)) + (error "You must have library `desktop.el' to use this command")) + (unless (file-name-absolute-p desktop-file) + (setq desktop-file (expand-file-name desktop-file bmkp-desktop-default-directory))) + (set-text-properties 0 (length desktop-file) nil desktop-file) + (let ((desktop-basefilename (file-name-nondirectory desktop-file)) ; Emacs < 22 + (desktop-base-file-name (file-name-nondirectory desktop-file)) ; Emacs 23+ + (desktop-dir (file-name-directory desktop-file)) + (desktop-restore-eager t) ; Don't bother with lazy restore. + (desktop-globals-to-save (bmkp-remove-if (lambda (elt) (memq elt bmkp-desktop-no-save-vars)) + desktop-globals-to-save))) + (bmkp-desktop-kill) + (desktop-clear) + (if (< emacs-major-version 22) (desktop-read) (desktop-read desktop-dir)))) + +;; Derived from code in `desktop-kill'. +(defun bmkp-desktop-kill () + "If `desktop-save-mode' is non-nil, do what `desktop-save' says to do. +In any case, release the lock on the desktop file. +This function does nothing in Emacs versions prior to Emacs 22." + ;; We assume here: `desktop.el' has been loaded and `desktop-dirname' is defined. + (when (and (boundp 'desktop-save-mode) ; Not defined in Emacs 20-21. + desktop-save-mode + (let ((exists (file-exists-p (desktop-full-file-name)))) + (or (eq desktop-save t) + (and exists (memq desktop-save '(ask-if-new if-exists))) + (and (or (memq desktop-save '(ask ask-if-new)) + (and exists (eq desktop-save 'ask-if-exists))) + (y-or-n-p "Save current desktop first? "))))) + (condition-case err + (if (or (< emacs-major-version 24) + (and (= emacs-major-version 24) (< emacs-minor-version 4))) + (desktop-save desktop-dirname 'RELEASE) + (desktop-save desktop-dirname 'RELEASE 'AUTOSAVE)) ; Emacs 24.4 introduced `AUTOSAVE'. + (file-error (unless (yes-or-no-p "Error while saving the desktop. IGNORE? ") + (signal (car err) (cdr err)))))) + ;; Just release lock, regardless of whether this Emacs process is the owner. + (when (fboundp 'desktop-release-lock) (desktop-release-lock))) ; Not defined for Emacs 20. + +;; Derived from code in `desktop-read'. +;;;###autoload (autoload 'bmkp-desktop-read "bookmark+") +(defun bmkp-desktop-read (file) + "Load desktop-file FILE, then run `desktop-after-read-hook'. +Return t if FILE was loaded, nil otherwise." + (interactive) + (unless (file-name-absolute-p file) ; Should never happen. + (setq file (expand-file-name file bmkp-desktop-default-directory))) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (setq desktop-dirname (file-name-directory file)) + (if (not (file-readable-p file)) + nil ; Return nil, meaning not loaded. + (let ((desktop-restore-eager t) ; Don't bother with lazy restore. + (desktop-first-buffer nil) + (desktop-buffer-ok-count 0) + (desktop-buffer-fail-count 0) + (desktop-save nil)) ; Prevent desktop saving during eval of desktop buffer. + (when (fboundp 'desktop-lazy-abort) (desktop-lazy-abort)) ; Emacs 22+. + (load file t t t) + (when (boundp 'desktop-file-modtime) ; Emacs 22+ + (setq desktop-file-modtime (nth 5 (file-attributes file)))) + ;; `desktop-create-buffer' puts buffers at end of the buffer list. + ;; We want buffers existing prior to evaluating the desktop (and not reused) to be placed + ;; at the end of the buffer list, so we move them here. + (mapc 'bury-buffer (nreverse (cdr (memq desktop-first-buffer (nreverse (buffer-list)))))) + (bmkp--pop-to-buffer-same-window (car (buffer-list))) + (run-hooks 'desktop-delay-hook) + (setq desktop-delay-hook ()) + (run-hooks 'desktop-after-read-hook) + (when (boundp 'desktop-buffer-ok-count) ; Emacs 22+ + (message "Desktop: %d buffer%s restored%s%s." desktop-buffer-ok-count + (if (= 1 desktop-buffer-ok-count) "" "s") + (if (< 0 desktop-buffer-fail-count) + (format ", %d failed to restore" desktop-buffer-fail-count) + "") + (if (and (boundp 'desktop-buffer-args-list) desktop-buffer-args-list) + (format ", %d to be restored lazily" (length desktop-buffer-args-list)) + ""))) + t))) ; Return t, meaning successfully loaded. + +;;;###autoload (autoload 'bmkp-desktop-delete "bookmark+") +(defun bmkp-desktop-delete (bookmark) + "Delete desktop bookmark BOOKMARK, and delete its desktop file. +Release the lock file in that desktop's directory. +\(This means that if you currently have locked a different desktop +in the same directory, then you will need to relock it.) +BOOKMARK is a bookmark name or a bookmark record." + (interactive + (let ((alist (bmkp-desktop-alist-only))) + (list (bmkp-read-bookmark-for-type "desktop" alist nil nil 'bmkp-desktop-history "Delete ")))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-desktop-alist-only)))) + (let ((desktop-file (bookmark-prop-get bookmark 'desktop-file))) + (unless desktop-file (error "Not a desktop-bookmark: `%s'" bookmark)) + ;; Release the desktop lock file in the same directory as DESKTOP-FILE. + ;; This will NOT be the right thing to do if a desktop file different from DESKTOP-FILE + ;; is currently locked in the same directory. + (let ((desktop-dir (file-name-directory desktop-file))) + (when (fboundp 'desktop-release-lock) (desktop-release-lock))) ; Not defined for Emacs 20. + (when (file-exists-p desktop-file) (delete-file desktop-file))) + (bookmark-delete bookmark)) + +;; Icicle search-hits bookmarks +(defun bmkp-jump-icicle-search-hits (bookmark) + "Handle an Icicles search-hits bookmark BOOKMARK." + (unless (and (boundp 'icicle-mode) icicle-mode (icicle-completing-p) + (condition-case nil (icicle-barf-if-outside-Completions-and-minibuffer) (error nil))) + (error "You can use this bookmark only in Icicle mode, and only during completion")) + (let ((raw-cands (bookmark-prop-get bookmark 'hits))) + (setq icicle-saved-completion-candidates + (if icicle-multi-completing-p + raw-cands ; But will not work if RAW-CANDS are not multi-completions. + (mapcar #'icicle-transform-multi-completion raw-cands))) + (if bmkp-icicles-search-hits-retrieve-more + (icicle-candidate-set-retrieve-more) + (icicle-candidate-set-retrieve)))) + +;;;###autoload (autoload 'bmkp-retrieve-icicle-search-hits "bookmark+") +(defun bmkp-retrieve-icicle-search-hits () ; Bound to `C-x C-M-<' during Icicles completion. + "Replace the current set of Icicles search hits by those from a bookmark. +You are prompted for the bookmark name. +This makes sense only if the buffer(s) or file(s) currently being +searched correspond to the recorded search hits." + (interactive) + (when (interactive-p) (icicle-barf-if-outside-Completions-and-minibuffer)) + (bmkp-retrieve-icicle-search-hits-1)) + +;;;###autoload (autoload 'bmkp-retrieve-more-icicle-search-hits "bookmark+") +(defun bmkp-retrieve-more-icicle-search-hits () ; Bound to `C-x C-<' during Icicles completion. + "Add the Icicles search hits from a bookmark to the current set of hits. +You are prompted for the bookmark name. +This makes sense only if the buffer(s) or file(s) currently being +searched correspond to the recorded search hits." + (interactive) + (when (interactive-p) (icicle-barf-if-outside-Completions-and-minibuffer)) + (bmkp-retrieve-icicle-search-hits-1 'MORE)) + +(defun bmkp-retrieve-icicle-search-hits-1 (&optional morep) + "Helper for `bmkp-retrieve-(more-)icicle-search-hits'." + (unless (and (boundp 'icicle-searching-p) icicle-searching-p) + (error "This command can be used only during Icicles search")) + (let* ((hits-bmks (bmkp-icicles-search-hits-alist-only)) + (bmk (let ((icicle-completion-candidates + icicle-completion-candidates) + (enable-recursive-minibuffers t)) + (bookmark-completing-read "Bookmark name" + (mapcar #'bmkp-bookmark-name-from-record hits-bmks) + hits-bmks + nil + nil + 'USE-NIL-ALIST-P))) + (bmkp-icicles-search-hits-retrieve-more morep)) + (bookmark-jump bmk))) + +;;;###autoload (autoload 'bmkp-set-icicle-search-hits-bookmark "bookmark+") +(defun bmkp-set-icicle-search-hits-bookmark () ; Bound to `C-x C-M->' during Icicles completion. + "Record the current set of Icicles search-hit candidates as a bookmark." + (interactive) + (unless (and (boundp 'icicle-searching-p) icicle-searching-p) + (error "This command can be used only during Icicles search")) + (unless icicle-completion-candidates (error "No search hits to record")) + (when (interactive-p) (icicle-barf-if-outside-Completions-and-minibuffer)) + (let ((bookmark-make-record-function 'bmkp-make-icicle-search-hits-record) + (enable-recursive-minibuffers t)) + (call-interactively #'bookmark-set))) + +(defun bmkp-make-icicle-search-hits-record () + "Create and return an Icicles search-hits bookmark record." + `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT nil nil 'NO-REGION) + (filename . ,bmkp-non-file-filename) + (hits . ,(mapcar #'bmkp-unpropertized-string icicle-completion-candidates)) + (handler . bmkp-jump-icicle-search-hits))) + +;; Variable-list bookmarks +(when (boundp 'zz-izones-var) ; In `zones.el'. + (defun bmkp-set-izones-bookmark (&optional variable msgp) + "Save a ring of buffer zones as a bookmark. +The zones can use markers or readable-marker objects for any +buffers. You need library `zones.el' to use the bookmark created. + +By default, the zones are those defined by the variable that is the +current value of `zz-izones-var', which defaults to `zz-izones'. With +a prefix arg you are prompted for a different variable to use. + +Non-interactively, VARIABLE is the restrictions variable to use." + (interactive (let ((var (or (and current-prefix-arg (zz-read-any-variable "Variable: " zz-izones-var)) + zz-izones-var))) + (list var t))) + (unless variable (setq variable zz-izones-var)) + (let ((bookmark-make-record-function + (lambda () + (bmkp-make-variable-list-record + `((,variable ; Format: (NUM BEGM ENDM), BEGM and ENDM are readable-marker objects. + . ,(mapcar (lambda (xx) + (let ((id (nth 0 xx)) + (beg (nth 1 xx)) + (end (nth 2 xx)) + (extra (nthcdr 3 xx))) + `(,id ,(zz-readable-marker beg) ,(zz-readable-marker end) ,@extra))) + (symbol-value variable)))))))) + (call-interactively #'bookmark-set) + (when (and msgp (not (featurep 'zones)) + (message "Bookmark created, but you need `zones.el' to use it"))))) + + ) + +;;;###autoload (autoload 'bmkp-wrap-bookmark-with-last-kbd-macro "bookmark+") +(defun bmkp-wrap-bookmark-with-last-kbd-macro (sequence bookmark &optional arg msgp) + ; Bound globally to `C-x x C-k'. + "Return a SEQUENCE bookmark that invokes BOOKMARK plus `last-kbd-macro'. +If bookmark SEQUENCE does not yet exist, create it. Else, update it. +You are prompted for the SEQUENCE and BOOKMARK names. + +BOOKMARK can be any kind of bookmark. A special case is when it is a +sequence bookmark: + + * If BOOKMARK is the same as SEQUENCE and is an existing sequence + bookmark then it is updated only by appending the keyboard macro to + the sequence. + + * If BOOKMARK is a sequence bookmark different from SEQUENCE then + SEQUENCE is updated to invoke the sequence in BOOKMARK plus + `last-kbd-macro' either before or after the other bookmarks of + SEQUENCE, according to the prefix arg, which is passed to + `bmkp-set-sequence-bookmark'." + (interactive (list (bmkp-completing-read-lax "Sequence bookmark" (bmkp-new-bookmark-default-names)) + (bmkp-completing-read-lax "Bookmark" (bmkp-new-bookmark-default-names)) + current-prefix-arg + 'MSGP)) + (unless last-kbd-macro (error "No keyboard macro defined")) + (let ((kbd-macro-vec (read-kbd-macro (format-kbd-macro last-kbd-macro) 'VECTOR))) + (bmkp-set-sequence-bookmark sequence (if (equal bookmark sequence) + (list kbd-macro-vec) + (list bookmark kbd-macro-vec)) + arg msgp))) + +;; Not used yet. +(defun bmkp-pop-to-readable-marker (readable-marker) + "Go to the marker recorded as persistent READABLE-MARKER. +The form of the input is (marker MARKER-BUFFER MARKER-POSITION." + (pop-to-buffer (cadr readable-marker)) + (goto-char (cadr (cdr readable-marker)))) + +;;;###autoload (autoload 'bmkp-set-sequence-bookmark "bookmark+") +(defun bmkp-set-sequence-bookmark (seqname bookmark-names &optional arg msgp) + ; Bound globally to `C-x x c s'. + "Create or update a sequence bookmark named SEQNAME from BOOKMARK-NAMES. +If a sequence bookmark named SEQNAME does not exist then create one. +Else act on the existing bookmarks in bookmark SEQNAME as follows: + + * no prefix arg: Append BOOKMARK-NAMES to those present. + * prefix arg < 0: Replace those present with BOOKMARK-NAMES. + * other prefix arg: Prepend BOOKMARK-NAMES to those present. + +You are prompted for SEQNAME and each of the BOOKMARK-NAMES. + +When entering each item of BOOKMARK-NAMES you can enter an existing or +future bookmark name, or you can enter the name of a function or a +named keyboard macro (provided what you type does not match a bookmark +name). If a function or keyboard macro, then a function bookmark is +created for it and that bookmark is included in the sequence. + +When the sequence bookmark is invoked (\"jumped to\"), its bookmarks +are invoked in order. In particular, any given bookmark is invoked +once for each of its occurrences in the sequence. + +From Lisp code: + +BOOKMARK-NAMES is generally a list of bookmarks or bookmark names + \(strings). + + Each item in BOOKMARK-NAMES can alternatively be one of the + following, in which case a function bookmark is created for it and is + used in the sequence. + + * a keyboard macro as a vector + * a function, which includes a lambda form or a symbol whose + function value is a function or a keyboard macro. + + If an item in BOOKMARK-NAMES is a sequence bookmark then its + bookmarks are used as if they were items of BOOKMARK-NAMES. + +MSGP non-nil means possibly interact with the user, showing messages." + (interactive (list + (if (< (prefix-numeric-value current-prefix-arg) 0) + (bookmark-completing-read "Replace existing sequence bookmark" + nil + (bmkp-sequence-alist-only) + nil + nil + 'USE-NIL-ALIST-P) + (bmkp-completing-read-lax "Create or update sequence bookmark" + (bmkp-new-bookmark-default-names) + (bmkp-sequence-alist-only))) + (bmkp-completing-read-bookmarks nil nil nil 'lax) + current-prefix-arg + 'MSGP)) + (let* ((seq (bmkp-get-bookmark-in-alist seqname 'NOERROR)) + (exists (and seq (bmkp-sequence-bookmark-p seq))) + (replacing t) + (bnames ()) + fun) + (dolist (bname bookmark-names) + (cond ((or (functionp (setq fun bname)) ; Function from Lisp. + (vectorp fun) ; Keyboard macro. + (functionp (setq fun (condition-case nil ; Function name from user + (bmkp-read-from-whole-string bname) + (error nil))))) + (let ((fun-bmk-name + (cond ((symbolp fun) (symbol-name fun)) ; Named function. Use its name. + ((vectorp fun) (format-kbd-macro fun)) ; Keyboard macro. Use human-readable strg + ;; Lambda form. Use as much as possible, but uniquify (no such symbol name). + (t (let ((ii 1) + (len (length bname)) + (trial (make-string (1+ bmkp-bookmark-name-length-max) 88))) + (while (and (< ii len) (> (length trial) bmkp-bookmark-name-length-max)) + (setq trial (make-temp-name (substring bname 0 (- ii))))) + (while (intern-soft + (setq trial (make-temp-name (substring bname 0 (- ii)))))) + trial))))) + (push (bmkp-bookmark-name-from-record (bmkp-make-function-bookmark fun-bmk-name fun)) + bnames))) + ((bmkp-sequence-bookmark-p bname) ; Sequence bookmark. + (setq bnames (append (reverse (bookmark-prop-get bname 'sequence)) bnames))) + ((stringp bname) (push bname bnames)) ; Bookmark name. + ((bmkp-get-bookmark bname 'NOERROR) ; Full bookmark. + (push (bmkp-bookmark-name-from-record bname) bnames)) + (t (error "Bad BOOKMARK-NAMES arg to `bmkp-set-sequence-bookmark': `%S'" + bookmark-names)))) ; Punt. + (setq bnames (nreverse bnames)) + (if (not exists) + (when msgp (message "Creating sequence bookmark...")) + (if (< (prefix-numeric-value arg) 0) + (when msgp (message "REPLACING existing sequence bookmark...") (sit-for 0.5)) + (when msgp (message "%sing to sequence bookmark..." (if arg "Prepend" "Append")) (sit-for 0.5)) + (setq replacing nil + bnames (if arg + (nconc bnames (bookmark-prop-get seq 'sequence)) + (nconc (bookmark-prop-get seq 'sequence) bnames))))) + (let ((bookmark-make-record-function `(lambda () (bmkp-make-sequence-record ',bnames)))) + (bookmark-set seqname)) + (when msgp (message "Sequence `%s' %s" seqname (if exists + (if replacing "replaced" "updated") + "created"))))) + +(defun bmkp-make-sequence-record (bookmark-names) + "Create and return a sequence bookmark record. +BOOKMARK-NAMES is a list of names of the bookmarks to be invoked in +sequence." + (let ((record `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT 0 nil 'NO-REGION) + (sequence . ,bookmark-names) + (handler . bmkp-jump-sequence)))) + record)) + +(when (require 'kmacro nil t) ; Emacs 22+ + + (defun bmkp-set-kmacro-bookmark (bookmark-name keyboard-macro &optional msg-p) + "Create a function bookmark named BOOKMARK-NAME from KEYBOARD-MACRO. +Prompt for BOOKMARK-NAME and the name of the keyboard macro to use. +With a prefix arg, use `last-kbd-macro' as the keyboard macro." + (interactive + (let ((bname (bmkp-completing-read-lax "Bookmark")) + (kmac (if current-prefix-arg + last-kbd-macro + (symbol-function (intern (completing-read "Keyboard macro name: " + obarray + (lambda (elt) + (and (fboundp elt) + (or (stringp (symbol-function elt)) + (vectorp (symbol-function elt)) + (get elt 'kmacro)))) + t)))))) + (list bname kmac 'MSG))) + (let* ((bmk (bmkp-get-bookmark-in-alist bookmark-name 'NOERROR)) + (exists (and bmk (bmkp-function-bookmark-p bmk)))) + (bmkp-make-function-bookmark bookmark-name keyboard-macro msg-p) + (when msg-p + (message "Function bookmark `%s' %s" bookmark-name (if exists "replaced" "created"))))) + + (defun bmkp-set-kmacro-list-bookmark (bookmark-name) + "Save all current keyboard macros as a kmacro-list bookmark." + (interactive (list (bmkp-completing-read-lax "Bookmark"))) + (let ((bookmark-make-record-function (lambda () + (bmkp-make-kmacro-list-record + (cons (kmacro-ring-head) kmacro-ring))))) + (bookmark-set bookmark-name))) + + (defun bmkp-make-kmacro-list-record (kmacros) + "Create and return a kmacro-list bookmark record. +KMACROS is the list of kmacros to save. It has the same form as +`kmacro-ring'. + +Each entry in KMACROS thus has the form (MACRO COUNTER FORMAT)." + (let ((record `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT nil nil 'NO-REGION) + (kmacros . ,kmacros) + (handler . bmkp-jump-kmacro-list)))) + record)) + + ) + +;;;###autoload (autoload 'bmkp-set-variable-list-bookmark "bookmark+") +(defun bmkp-set-variable-list-bookmark (variables) + "Save a list of variables as a bookmark. +Interactively, read the variables to save, using +`bmkp-read-variables-completing'." + (interactive (list (bmkp-read-variables-completing))) + (let ((bookmark-make-record-function (lexical-let ((vars variables)) + (lambda () (bmkp-make-variable-list-record vars))))) + (call-interactively #'bookmark-set))) + +;; Not used in the Bookmark+ code. Available for users to create varlist bookmark non-interactively. +(defun bmkp-create-variable-list-bookmark (bookmark-name vars vals &optional buffer-name) + "Create a variable-list bookmark named BOOKMARK-NAME from VARS and VALS. +VARS and VALS are corresponding lists of variables and their values. + +Optional arg BUFFER-NAME is the buffer name to use for the bookmark (a +string). This is useful if some of the variables are buffer-local. +If BUFFER-NAME is nil, the current buffer name is recorded." + (eval `(multiple-value-bind ,vars ',vals + (let ((bookmark-make-record-function (lexical-let ((vs vars) + (buf buffer-name)) + (lambda () (bmkp-make-variable-list-record vs buf))))) + (bookmark-set ,bookmark-name))))) + +(defun bmkp-read-variables-completing (&optional option) + "Read variable names with completion, and return them as a list of symbols. +Reads names one by one, until you hit `RET' twice consecutively. +Non-nil argument OPTION means read only user option names." + (bookmark-maybe-load-default-file) + (let ((var (bmkp-read-variable "Variable (RET for each, empty input to finish): " option)) + (vars ()) + old-var) + (while (not (string= "" var)) + (add-to-list 'vars var) + (setq var (bmkp-read-variable "Variable: " option))) + (nreverse vars))) + +(defun bmkp-read-variable (prompt &optional option default-value) + "Read name of a variable and return it as a symbol. +Prompt with string PROMPT. +With non-nil OPTION, read the name of a user option. +The default value is DEFAULT-VALUE if non-nil, or the nearest symbol +to the cursor if it is a variable." + (setq option (if option 'user-variable-p 'boundp)) + (let ((symb (cond ((fboundp 'symbol-nearest-point) + (symbol-nearest-point)) ; In `thingatpt+.el'. + ((fboundp 'symbol-at-point) (symbol-at-point)) + (t nil))) + (enable-recursive-minibuffers t) + (icicle-unpropertize-completion-result-flag t)) + (when (and default-value (symbolp default-value)) + (setq default-value (symbol-name default-value))) + (intern (completing-read prompt obarray option t nil 'minibuffer-history + (or default-value (and (funcall option symb) (symbol-name symb))) + t)))) + +(defun bmkp-make-variable-list-record (variables &optional buffer-name) + "Create and return a variable-list bookmark record. +VARIABLES is the list of variables to save. +Each entry in VARIABLES is either a variable (a symbol) or a cons + whose car is a variable and whose cdr is the variable's value. + +Optional arg BUFFER-NAME is the buffer to use for the bookmark. This +is useful if some of the variables are buffer-local. If BUFFER-NAME +is nil, the current buffer is used." + (let ((record `(,@(bookmark-make-record-default 'NO-FILE 'NO-CONTEXT nil nil 'NO-REGION) + (filename . ,bmkp-non-file-filename) + (variables . ,(or (bmkp-printable-vars+vals variables) + (error "No variables to bookmark"))) + (handler . bmkp-jump-variable-list)))) + (when buffer-name (let ((bname (assq 'buffer-name record))) (setcdr bname buffer-name))) + record)) + +(defun bmkp-printable-vars+vals (variables) + "Return an alist of printable VARIABLES paired with their values. +Display a message for any variables that are not printable. +VARIABLES is the list of variables. Each entry in VARIABLES is either + a variable (a symbol) or a cons whose car is a variable and whose cdr + is the variable's value." + (let ((vars+vals ()) + (unprintables ())) + (dolist (var variables) + (let ((val (if (consp var) (cdr var) (symbol-value var)))) + (if (bmkp-readable-p val) + (add-to-list 'vars+vals (if (consp var) var (cons var val))) + (add-to-list 'unprintables var)))) + (when unprintables (message "Unsavable (unreadable) vars: %S" unprintables) (sit-for 3)) + vars+vals)) + +;; Same as `savehist-printable' in `savehist-20+.el', except added `print-circle' and `print-gensym' bindings. +(defun bmkp-readable-p (value) + "Return non-nil if VALUE is Lisp-readable if printed using `prin1'." + (cond ((numberp value)) + ((symbolp value)) + ((and (stringp value) ; String with no text properties. + (if (fboundp 'equal-including-properties) ; Emacs 22+. + (equal-including-properties value (substring-no-properties value)) + (and (null (text-properties-at 0 value)) + (= 0 (next-property-change 0 value)))))) + (t (with-temp-buffer + (condition-case nil + (let ((print-readably t) + (print-level nil) + (print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag)) + (prin1 value (current-buffer)) ; Print value into a buffer and try to read back. + (read (point-min-marker)) + t) + (error nil)))))) ; Could not print and read back. + +(when (require 'kmacro nil t) ; Emacs 22 + + (defun bmkp-jump-kmacro-list (bookmark) + "Jump to kmacro-list bookmark BOOKMARK, restoring the keyboard macros. +Handler function for record returned by +`bmkp-make-kmacro-list-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let ((buf (bmkp-get-buffer-name bookmark)) + (kbd-macs (bookmark-prop-get bookmark 'kmacros))) + (unless (and buf (get-buffer buf)) + (message "Bookmarked for non-existent buffer `%s', so using current buffer" buf) (sit-for 3) + (setq buf (current-buffer))) + (with-current-buffer buf + (let ((kmacs kbd-macs)) + (when last-kbd-macro + (kmacro-push-ring (list last-kbd-macro kmacro-counter kmacro-counter-format-start))) + (kmacro-split-ring-element (pop kmacs)) + (dolist (kmac kmacs) (kmacro-push-ring kmac)))) + (message "Keyboard macros restored in buffer `%s': %S" buf (mapcar #'car kbd-macs)) + (sit-for 3))) + + ) + + +;; REPLACES ORIGINAL in `info.el': +;; +;; Respect `Info-bookmark-use-only-node-not-file-flag'. +;; +;; This code and the definition of `Info-bookmark-use-only-node-not-file-flag' are also in `info+.el', +;; so that their feature is available if you use either `Info+' or `Bookmark+'. +;; +;; Note: This function name doesn't respect the naming convention for bookmark handler functions. +;; This name gives the impression that this is a jump command. +;; +;;;###autoload (autoload 'Info-bookmark-jump "bookmark+") +(defun Info-bookmark-jump (bookmark) + "Handler function for record returned by `Info-bookmark-make-record'. +BOOKMARK is a bookmark name or a bookmark record. + +If `Info-bookmark-use-only-node-not-file-flag' is nil, and the +recorded Info file is readable, then use it. If not, then go to the +recorded Info node in the manual for the current Emacs version." + (require 'info) ; Needed only for Emacs 20-22: not autoloaded for `Info-find-node'. + (let* ((absfile (bookmark-prop-get bookmark 'filename)) + (file (if (or Info-bookmark-use-only-node-not-file-flag (not (file-readable-p absfile))) + (file-name-nondirectory absfile) + absfile)) + (info-node (bookmark-prop-get bookmark 'info-node)) + (buf (save-window-excursion ; Vanilla FIXME: doesn't work with frames! + (Info-find-node file info-node) (current-buffer)))) + (bookmark-default-handler `("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bookmark))))) + +(defun bmkp-jump-variable-list (bookmark) + "Jump to variable-list bookmark BOOKMARK, restoring the recorded values. +Handler function for record returned by +`bmkp-make-variable-list-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let ((buf (bmkp-get-buffer-name bookmark)) + (vars+vals (bookmark-prop-get bookmark 'variables))) + (unless (get-buffer buf) + (message "Bookmarked for non-existent buffer `%s', so using current buffer" buf) (sit-for 3) + (setq buf (current-buffer))) + (with-current-buffer buf + (dolist (var+val vars+vals) + (set (car var+val) (cdr var+val)))) + (message "Variables restored in buffer `%s': %S" buf (mapcar #'car vars+vals)) + (sit-for 3))) + +;; URL browse support +(defun bmkp-make-url-browse-record (url) + "Create and return a url bookmark for `browse-url' to visit URL. +The handler is `bmkp-jump-url-browse'." + (require 'browse-url) + (let ((url-0 (copy-sequence url))) + (set-text-properties 0 (length url) () url-0) + `((filename . ,bmkp-non-file-filename) + (location . ,url-0) + (handler . bmkp-jump-url-browse)))) + +(defun bmkp-jump-url-browse (bookmark) + "Handler function for record returned by `bmkp-make-url-browse-record'. +BOOKMARK is a bookmark name or a bookmark record." + (require 'browse-url) + (let ((url (bookmark-prop-get bookmark 'location))) + (browse-url url))) + + +;; EWW support +(when (> emacs-major-version 24) ; Emacs 25+ + + ;; This is set by `bmkp-eww-rename-buffer' and used in `bmkp-jump-eww' for local var `after-render-function'. + (defvar bmkp-eww-new-buf-name nil + "If non-nil, the name of the EWW buffer to jump to.") + (make-variable-buffer-local 'bmkp-eww-new-buf-name) + + ;; This is set by `bmkp-jump-eww' and used in `bmkp-eww-rename-buffer'. + (defvar bmkp-eww-jumping-p nil + "Non-nil only if we are currently jumping to an EWW bookmark.") + (make-variable-buffer-local 'bmkp-eww-jumping-p) + + (defun bmkp-eww-title () + "Return the web-page title of the current `eww-mode' buffer." + (plist-get eww-data :title)) + + (defun bmkp-eww-url () + "Return the URL of the current `eww-mode' buffer." + (eww-current-url)) + + (defun bmkp-make-eww-record () + "Make a record for an EWW buffer." + `(,(bmkp-eww-title) + (buffer-name . ,(bmkp-eww-new-buffer-name)) + ,@(bookmark-make-record-default 'NO-FILE) + (location . ,(bmkp-eww-url)) + (handler . bmkp-jump-eww))) + + (add-hook 'eww-mode-hook (lambda () (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-eww-record))) + + (defun bmkp-eww-new-buffer-name () + "Return a new buffer name for the current `eww-mode' buffer. +The name format is determined by option `bmkp-eww-buffer-renaming'." + (concat "*eww*" (and bmkp-eww-buffer-renaming + (concat "-" + (bmkp-eww-title) + (let ((url (bmkp-eww-url))) + (and (eq 'url bmkp-eww-buffer-renaming) + (concat " " (if (>= (length url) 20) (substring url -20) url)))))))) + + (defun bmkp-jump-eww (bookmark) + "Handler function for record returned by `bmkp-make-eww-record'. +BOOKMARK is a bookmark name or a bookmark record." + (require 'eww) + (let ((buffer (or (and (not bmkp-eww-generate-buffer-flag) + (get-buffer (bmkp-get-buffer-name bookmark))) + (generate-new-buffer "*eww*"))) ; Might get renamed later. + ;; VAR `bmkp-eww-new-buf-name' is free here. It is bound in `bmkp-eww-rename-buffer'. + (after-render-function `(lambda () + (when (and bmkp-eww-buffer-renaming bmkp-eww-new-buf-name) + (kill-buffer) + (set-buffer bmkp-eww-new-buf-name)) + (bookmark-default-handler + `("" (buffer . ,(current-buffer)) + . ,(bmkp-bookmark-data-from-record ,(car bookmark)))) + (dolist (var '(bmkp-eww-jumping-p eww-after-render-hook)) + (kill-local-variable var))))) + (setq bmkp-eww-jumping-p t) + (with-current-buffer buffer + (eww-mode) + (save-window-excursion ; Save window because it calls `pop-to-buffer-same-window'. + (eww (bookmark-location bookmark))) + (add-hook 'eww-after-render-hook after-render-function 'APPEND 'LOCAL)))) + + (defun bmkp-eww-rename-buffer (&rest _ignored) + "Rename current buffer according to option `bmkp-eww-buffer-renaming'. +When jumping to EWW bookmark with nil `bmkp-eww-generate-buffer-flag', +if the buffer has already been visited, set `bmkp-eww-new-buf-name' so +that `bmkp-jump-eww' will use the already visited buffer." + (when bmkp-eww-buffer-renaming + (let ((new-bname (bmkp-eww-new-buffer-name))) + (condition-case nil + (rename-buffer new-bname) + ;; VAR `bmkp-eww-jumping-p' is free here. It is set in `bmkp-jump-eww'. + (error (if (and bmkp-eww-jumping-p (not bmkp-eww-generate-buffer-flag)) + (setq bmkp-eww-new-buf-name new-bname) ; For `after-render-function' in `bmkp-jump-eww'. + (rename-buffer (generate-new-buffer-name new-bname)))))))) + + ;; The EWW buffer is renamed on each visit, if `bmkp-eww-buffer-renaming' is non-nil. + (eval-after-load "eww" + '(when (> emacs-major-version 24) ; Emacs 25+ + (add-hook 'eww-after-render-hook 'bmkp-eww-rename-buffer) + (advice-add 'eww-restore-history :after 'bmkp-eww-rename-buffer))) + + + ;; Eval this so that even if the library is byte-compiled with Emacs 20, + ;; loading it into Emacs 22+ will define variable `bmkp-eww-auto-bookmark-mode'. + (eval '(define-minor-mode bmkp-eww-auto-bookmark-mode + "Toggle automatically setting a bookmark when you visit a URL with EWW. +The bookmark name is the title of the web page. + +If option `bmkp-eww-auto-type' is `create-or-update' then such a +bookmark is created for the URL if none exists. If the option value +is `update-only' then no new bookmark is created automatically, but an +existing bookmark is updated. (Updating a bookmark increments the +recorded number of visits.) You can toggle the option using +`\\[bmkp-toggle-eww-auto-type]'." + :init-value nil :global t :group 'bookmark-plus :require 'bookmark+ + :lighter bmkp-automatic-bookmark-mode-lighter + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +Bookmark bug: \ +&body=Describe bug here, starting with `emacs -Q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Download" "https://www.emacswiki.org/emacs/download/bookmark%2b.el") + :link '(url-link :tag "Description" "https://www.emacswiki.org/emacs/BookmarkPlus") + :link '(emacs-commentary-link :tag "Commentary" "bookmark+") + (cond (bmkp-eww-auto-bookmark-mode + (add-hook 'eww-after-render-hook 'bmkp-set-eww-bookmark-here) + (advice-add 'eww-restore-history :after 'bmkp-set-eww-bookmark-here)) + (t + (remove-hook 'eww-after-render-hook 'bmkp-set-eww-bookmark-here) + (advice-remove 'eww-restore-history 'bmkp-set-eww-bookmark-here))) + (when (interactive-p) + (message "Automatic EWW bookmarking is now %s" + (if bmkp-eww-auto-bookmark-mode + (if (eq bmkp-eww-auto-type 'update-only) + "ON, updating only" + "ON, creating or UPDATING") + "OFF"))))) + + (defun bmkp-set-eww-bookmark-here (&optional nomsg) + "Set an EWW bookmark for the URL of the current EWW buffer. +The current buffer is assumed to be in `eww-mode' and visiting a URL." + (interactive) + (let* ((bname (bmkp-eww-title)) + (url (bmkp-eww-url)) + (bmk (bmkp-get-bookmark bname 'NO-ERROR)) + (visits (and bmk (bookmark-prop-get bmk 'visits)))) + (when bname + (cond ((and (not visits) (eq bmkp-eww-auto-type 'create-or-update)) + (bookmark-set bname) + (unless nomsg (message "Created EWW bookmark `%s'" bname))) + (visits + (bmkp-record-visit bname 'BATCHP) + (bmkp-refresh/rebuild-menu-list bname nil) + (bmkp-maybe-save-bookmarks) + (unless nomsg (message "Updated EWW bookmark `%s'" bname))))))) + + (defun bmkp-toggle-eww-auto-type (&optional msgp) + "Toggle the value of option `bmkp-eww-auto-type'." + (interactive "p") + (setq bmkp-eww-auto-type (if (eq bmkp-eww-auto-type 'create-or-update) 'update-only 'create-or-update)) + (when msgp (message "`bmkp-eww-auto-bookmark-mode' now %s" + (if (eq bmkp-eww-auto-type 'create-or-update) + "CREATES, as well as updates, EWW bookmarks" + "only UPDATES EXISTING EWW bookmarks")))) + + + ;; You can use this to convert existing EWW bookmarks to Bookmark+ bookmarks. + ;; + (defun bmkp-convert-eww-bookmarks (eww-file bmk-file &optional msgp) + "Add bookmarks from EWW-FILE to BMK-FILE. +EWW-FILE is a file of \"bookmarks\" created by EWW, which are not +compatible with Emacs bookmarks. EWW-FILE is not modified. + +BMK-FILE is a Bookmark+ bookmarks file, which is an ordinary Emacs +bookmarks file (possibly with Bookmark+-specific bookmarks). + +If BMK-FILE exists then it is updated to include the converted +bookmarks. If it does not exist then it is created." + (interactive + (let* ((std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + bookmark-default-file + std-default) + bmkp-last-bookmark-file))) + (list (bmkp-read-bookmark-file-name "EWW bookmark file: " + nil + (expand-file-name "eww-bookmarks" user-emacs-directory) + t) + (bmkp-read-bookmark-file-name "Emacs bookmark file to update: " + (or (file-name-directory default) "~/") + (if (bmkp-same-file-p bmkp-current-bookmark-file + bmkp-last-bookmark-file) + (bmkp-default-bookmark-file) + bmkp-last-bookmark-file)) + t))) + (when (file-directory-p eww-file) (error "`%s' is a directory, not a file" eww-file)) + (unless (file-readable-p eww-file) (error "Cannot read bookmark file `%s'" eww-file)) + (when (file-directory-p bmk-file) (error "`%s' is a directory, not a file" bmk-file)) + (unless (file-readable-p bmk-file) (bmkp-empty-file bmk-file)) ; Create empty bookmark file. + (with-temp-buffer + (insert-file-contents eww-file) + (let ((bookmark-alist ()) + url title created bmk) + (dolist (ebmk (read (current-buffer))) + (setq url (plist-get ebmk :url) + title (plist-get ebmk :title) + created (date-to-time (plist-get ebmk :time)) + bmk `(,title + ,@(bookmark-make-record-default 'NO-FILE) + (location . ,url) + (handler . bmkp-jump-eww))) + (let ((buf-cell (assq 'buffer-name bmk))) (setcdr buf-cell "*eww*")) + (let ((created-cell (assq 'created bmk))) (setcdr created-cell created)) + (push bmk bookmark-alist)) + (bookmark-write-file bmk-file 'ADD))) + (when msgp (message "Wrote Bookmark file `%s'" bmk-file))) + + ) + +;; W3M support +(defun bmkp-make-w3m-record () + "Make a special entry for w3m buffers." + (require 'w3m) ; For `w3m-current-url'. + `(,w3m-current-title + ,@(bookmark-make-record-default 'NO-FILE) + (location . ,w3m-current-url) + (handler . bmkp-jump-w3m))) + +(add-hook 'w3m-mode-hook (lambda () (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-w3m-record))) + +(defun bmkp-w3m-set-new-buffer-name () + "Set the w3m buffer name according to the number of W3M buffers already open." + (require 'w3m) ; For `w3m-list-buffers'. + (let ((len (length (w3m-list-buffers 'nosort)))) + (if (= len 0) "*w3m*" (format "*w3m*<%d>" (1+ len))))) + +(defalias 'bmkp-jump-w3m-new-session 'bmkp-jump-w3m-new-buffer) +(defun bmkp-jump-w3m-new-buffer (bookmark) + "Jump to W3M bookmark BOOKMARK in a new buffer (in a new W3M tab)." + (require 'w3m) + (let ((buf (bmkp-w3m-set-new-buffer-name))) + (w3m-browse-url (bookmark-location bookmark) 'newsession) + (while (not (get-buffer buf)) (sit-for 1)) ; Be sure we have the W3M buffer. + (with-current-buffer (get-buffer-create buf) + (goto-char (point-min)) + ;; Wait until data arrives in buffer, before setting region. + (while (eq (line-beginning-position) (line-end-position)) (sit-for 1))) + (bookmark-default-handler `("" (buffer . ,buf) . ,(bmkp-bookmark-data-from-record bookmark))))) + +(defalias 'bmkp-jump-w3m-only-one-tab 'bmkp-jump-w3m-only-one-buffer) +(defun bmkp-jump-w3m-only-one-buffer (bookmark) + "Close all W3M sessions and jump to BOOKMARK in a new W3M buffer." + (require 'w3m) + (w3m-quit 'force) ; Be sure we start with an empty W3M buffer. + (w3m-browse-url (bookmark-location bookmark)) + (with-current-buffer (get-buffer-create "*w3m*") (while (eq (point-min) (point-max)) (sit-for 1))) + (bookmark-default-handler `("" (buffer . "*w3m*") . ,(bmkp-bookmark-data-from-record bookmark)))) + +(defalias 'bmkext-jump-w3m 'bmkp-jump-w3m) +(defun bmkp-jump-w3m (bookmark) + "Handler function for record returned by `bmkp-make-w3m-record'. +BOOKMARK is a bookmark name or a bookmark record. +Use a new buffer (tab) if `bmkp-w3m-allow-multiple-buffers-flag' is +non-nil." + (require 'w3m) + (if bmkp-w3m-allow-multiple-buffers-flag + (bmkp-jump-w3m-new-buffer bookmark) + (bmkp-jump-w3m-only-one-buffer bookmark))) + + +;; GNUS support for Emacs < 24. More or less the same as `gnus-summary-bookmark-make-record' in Emacs 24+. +;; But this: +;; +;; * Works for other Emacs versions as well. +;; * Requires `gnus.el'. +;; * Adds a `bmkp-non-file-filename' `filename' entry. +;; * Uses `bmkp-jump-gnus', not `gnus-summary-bookmark-jump' as the handler. +;; +(defun bmkp-make-gnus-record () + "Make a bookmark entry for a Gnus summary buffer. +Current buffer can be the article buffer or the summary buffer." + (require 'gnus) + (let ((pos nil) + buf) + ;; If in article buffer, record point and buffer, then go to summary buffer + ;; and record bookmark there. + (unless (and (if (fboundp 'derived-mode-p) + (derived-mode-p 'gnus-summary-mode) + (eq major-mode 'gnus-summary-mode)) + gnus-article-current) + (setq buf "art" + bookmark-yank-point (point) + bookmark-current-buffer (current-buffer)) + (save-restriction (widen) (setq pos (point))) ; Position in article buffer. + (gnus-article-show-summary)) + (let* ((grp (car gnus-article-current)) + (art (cdr gnus-article-current)) + (head (gnus-summary-article-header art)) + (id (mail-header-id head))) + (unless buf (setq buf "sum")) + `((elt (gnus-summary-article-header) 1) ; Subject. + ,@(condition-case + nil + (bookmark-make-record-default ; POS = nil if started in summary buffer. + 'NO-FILE 'NO-CONTEXT pos nil 'NO-REGION) + (wrong-number-of-arguments (bookmark-make-record-default 'POINT-ONLY))) + (location . ,(format "Gnus-%s %s:%d:%s" buf grp art id)) + (filename . ,bmkp-non-file-filename) (group . ,grp) (article . ,art) (message-id . ,id) + (handler . bmkp-jump-gnus))))) ; Vanilla Emacs 24+ uses `gnus-summary-bookmark-jump'. + + +;; Vanilla Emacs 24+ uses `gnus-summary-bookmark-make-record' for these hooks. +;; Better to use `bmkp-make-gnus-record' even for Emacs 24+, because `bmkp-jump-gnus' is better than +;; `gnus-summary-bookmark-jump' (no `sit-for' if article buffer not needed). + +;; $$$$$$ (unless (> emacs-major-version 23) ; Emacs 24 has `gnus-summary-bookmark-make-record'. +(add-hook 'gnus-summary-mode-hook (lambda () + (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-gnus-record))) + +;; $$$$$$ (unless (> emacs-major-version 23) ; Emacs 24 has `gnus-summary-bookmark-make-record'. +(add-hook 'gnus-article-mode-hook (lambda () + (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-gnus-record))) + +;; More or less the same as `gnus-summary-bookmark-jump' in Emacs 24+. +;; But this does not `sit-for' unless BUF is "Gnus-art". +;; +(defun bmkp-jump-gnus (bookmark) + "Handler function for record returned by `bmkp-make-gnus-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let* ((group (bookmark-prop-get bookmark 'group)) + (article (bookmark-prop-get bookmark 'article)) + (id (bookmark-prop-get bookmark 'message-id)) + (loc (bookmark-prop-get bookmark 'location)) + (buf (if loc (car (split-string loc)) (bookmark-prop-get bookmark 'buffer)))) + (if (< emacs-major-version 22) (gnus-fetch-group group) (gnus-fetch-group group (list article))) + (gnus-summary-insert-cached-articles) + (gnus-summary-goto-article id nil 'force) + ;; Go to article buffer if appropriate. Wait for it to be ready, so `bookmark-default-handler' has time + ;; to set the right position. + (when (equal buf "Gnus-art") (sit-for 1) (other-window 1)) + (bookmark-default-handler `("" (buffer . ,buf) . ,(bmkp-bookmark-data-from-record bookmark))))) + +(defun bmkext-jump-gnus (bookmark) ; Compatibility code. + "`gnus-summary-bookmark-jump' if defined, else `bmkp-jump-gnus'." + (if (fboundp 'gnus-summary-bookmark-jump) + (gnus-summary-bookmark-jump bookmark) ; Emacs 24 + (bmkp-jump-gnus bookmark))) + + +;; `man' and `woman' support for Emacs < 24. + +(when (> emacs-major-version 20) + (defun bmkp-make-woman-record () + "Create bookmark record for `man' page bookmark created by `woman'." + `(,@(bookmark-make-record-default 'NO-FILE) + (filename . ,woman-last-file-name) (handler . bmkp-jump-woman))) + + (unless (> emacs-major-version 23) + (add-hook 'woman-mode-hook (lambda () + (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-woman-record))))) + +(defun bmkp-make-man-record () + "Create bookmark record for `man' page bookmark created by `man'." + `(,@(bookmark-make-record-default 'NO-FILE) + (filename . ,bmkp-non-file-filename) + (man-args . ,Man-arguments) (handler . bmkp-jump-man))) + +(unless (> emacs-major-version 23) + (add-hook 'Man-mode-hook (lambda () (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-man-record)))) + +(defun bmkext-jump-woman (bookmark) ; Compatibility code. + "`woman-bookmark-jump' if defined, else `bmkp-jump-woman'." + (if (fboundp 'woman-bookmark-jump) + (woman-bookmark-jump bookmark) ; Emacs 24 + (bmkp-jump-woman bookmark))) + +(defun bmkp-jump-woman (bookmark) + "Handler function for `man' page bookmark created by `woman'. +BOOKMARK is a bookmark name or a bookmark record." + (unless (> emacs-major-version 20) + (error "`woman' bookmarks are not supported in Emacs prior to Emacs 21")) + (bookmark-default-handler + `("" (buffer . ,(save-window-excursion (woman-find-file (bookmark-get-filename bookmark)) + (current-buffer))) + . ,(bmkp-bookmark-data-from-record bookmark)))) + +(defun bmkext-jump-man (bookmark) ; Compatibility code. + "`Man-bookmark-jump' if defined, else `bmkp-jump-man'." + (if (fboundp 'Man-bookmark-jump) + (Man-bookmark-jump bookmark) ; Emacs 24 + (bmkp-jump-man bookmark))) + +(defun bmkp-jump-man (bookmark) + "Handler function for `man' page bookmark created by `man'. +BOOKMARK is a bookmark name or a bookmark record." + (require 'man) + (let* ((man-args (bookmark-prop-get bookmark 'man-args)) + ;; `Man-notify-method' binding needs to be in effect during the calls to both + ;; `Man-getpage-in-background' and `accept-process-output'. + (Man-notify-method (case bmkp-jump-display-function + ((nil display-buffer) 'quiet) + (bmkp--pop-to-buffer-same-window 'pushy) + ((bmkp-select-buffer-other-window + switch-to-buffer-other-window + pop-to-buffer) + 'friendly) + (t 'quiet))) + (buf (Man-getpage-in-background man-args)) + (proc (and (bufferp buf) ; Emacs 24+ + (get-buffer-process buf)))) + (if proc + (while (and proc (eq (process-status proc) 'run)) (accept-process-output proc)) + (while (get-process "man") (sit-for 0.2))) + (bookmark-default-handler (bmkp-get-bookmark bookmark)))) + +(defun bmkp-dired-remember-*-marks (beg end) + "Return a list of the files and subdirs marked `*' in Dired." + (if (fboundp 'dired--unhide) ; Emacs 27+ uses invisible text, not `selective-display'. + (with-silent-modifications (dired--unhide (point-min) (point-max))) + (when selective-display (let ((inhibit-read-only t)) (subst-char-in-region beg end ?\r ?\n)))) + (let ((mfiles ()) + fil) + (save-excursion (goto-char beg) + (while (re-search-forward "^\\*" end t) ; Not `dired-re-mark' - match only `*' marks. + (when (setq fil (dired-get-filename nil t)) (push fil mfiles)))) + (nreverse mfiles))) + +(defun bmkp-make-dired-record () + "Create and return a Dired bookmark record." + (let ((hidden-dirs (save-excursion (dired-remember-hidden)))) + (unwind-protect + (let ((dir (expand-file-name (if (consp dired-directory) + (file-name-directory (car dired-directory)) + dired-directory))) + (subdirs (bmkp-dired-subdirs)) + (mfiles (bmkp-dired-remember-*-marks (point-min) (point-max)))) + `(,dir + ,@(bookmark-make-record-default 'NO-FILE) + (filename . ,dir) (dired-directory . ,dired-directory) + (dired-marked . ,mfiles) (dired-switches . ,dired-actual-switches) + (dired-subdirs . ,subdirs) (dired-hidden-dirs . ,hidden-dirs) + (handler . bmkp-jump-dired))) + (save-excursion ; Hide subdirs that were hidden. + (dolist (dir hidden-dirs) (when (dired-goto-subdir dir) (dired-hide-subdir 1))))))) + +;;;###autoload (autoload 'bmkp-dired-subdirs "bookmark+") +(defun bmkp-dired-subdirs () + "Alist of inserted subdirectories, without their positions (markers). +This is like `dired-subdir-alist' but without the top-level dir and +without subdir positions (markers)." + (interactive) + (let ((subdir-alist (cdr (reverse dired-subdir-alist))) ; Remove top. + (subdirs-wo-posns ())) + (dolist (sub subdir-alist) (push (list (car sub)) subdirs-wo-posns)) + subdirs-wo-posns)) + +(add-hook 'dired-mode-hook (lambda () (set (make-local-variable 'bookmark-make-record-function) + 'bmkp-make-dired-record))) + +(defun bmkp-jump-dired (bookmark) + "Jump to Dired bookmark BOOKMARK. +Handler function for record returned by `bmkp-make-dired-record'. +BOOKMARK is a bookmark name or a bookmark record." + (let ((dir (bookmark-prop-get bookmark 'dired-directory)) + (mfiles (bookmark-prop-get bookmark 'dired-marked)) + (switches (bookmark-prop-get bookmark 'dired-switches)) + (subdirs (bookmark-prop-get bookmark 'dired-subdirs)) + (hidden-dirs (bookmark-prop-get bookmark 'dired-hidden-dirs))) + (case bmkp-jump-display-function + ((nil bmkp--pop-to-buffer-same-window display-buffer) + (dired dir switches)) + ((bmkp-select-buffer-other-window pop-to-buffer switch-to-buffer-other-window) + (dired-other-window dir switches)) + (t (dired dir switches))) + (let ((inhibit-read-only t)) + (dired-insert-old-subdirs subdirs) + (dired-mark-remembered (mapcar (lexical-let ((dd dir)) + (lambda (mf) (cons (expand-file-name mf dd) 42))) + mfiles)) + (save-excursion (dolist (dir hidden-dirs) (when (dired-goto-subdir dir) (dired-hide-subdir 1))))) + (let ((pos (bookmark-get-position bookmark))) (when pos (goto-char pos))))) + +(defun bmkp-read-bookmark-for-type (type alist &optional other-win pred hist action prompt) + "Read name of a bookmark of type TYPE in ALIST, and return the bookmark. +TYPE is a string used in the prompt: \"Jump to TYPE bookmark: \". +ALIST is the alist used for completion. If nil then raise an error to + let the user know there are no bookmarks of type TYPE. +Non-nil OTHER-WIN means append \" in another window\" to the prompt. +Non-nil PRED is a predicate used for bookmark-name completion. +Non-nil HIST is a history symbol. Default is `bookmark-history'. +Non-nil ACTION is the action mentioned in the prompt; nil: `Jump to '. +Non-nil PROMPT is an alternative prompt." + (unless alist (error "No bookmarks of type %s" type)) + (bmkp-bookmark-record-from-name + (bookmark-completing-read (or prompt (concat (or action "Jump to ") type " bookmark" + (and other-win " in another window"))) + (bmkp-default-bookmark-name alist) + alist pred hist) + 'NOERROR nil alist)) + +;;;###autoload (autoload 'bmkp-jump-to-type "bookmark+") +(defun bmkp-jump-to-type (bookmark &optional flip-use-region-p) ; `C-x j :' + "Jump to a bookmark of a given type. You are prompted for the type. +Otherwise, this is the same as `bookmark-jump' - see that, in +particular, for info about using a prefix argument. + +When prompted for the type, you can use completion against the known +bookmark types (see function `bmkp-types-alist'). + +Completion is lax, so you can also enter the name of a bookmark +`handler' or `file-handler' function, without completion. Bookmarks +with that entry value are then the jump candidates. + +When called from Lisp, BOOKMARK must be a bookmark record, not a +bookmark name, or else an error is raised." + (interactive + (let* ((completion-ignore-case t) + (type-cands (bmkp-types-alist)) + (icicle-unpropertize-completion-result-flag t) + (type (completing-read "Type of bookmark: " type-cands)) + (history (assoc-default type type-cands)) + (alist (if history + (funcall + (intern (format "bmkp-%s-alist-only" type))) + bookmark-alist)) + (bmk (bmkp-read-bookmark-for-type + type alist nil + ;; PREDICATE if not a recognized type name. + (and (not history) + (bmkp-handler-pred (intern type))) + history))) + (list bmk (or (equal type "Region") current-prefix-arg)))) + (when (stringp bookmark) (error "Not a bookmark record (perhaps a bookmark name): `%s'" bookmark)) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-jump-to-type-other-window "bookmark+") +(defun bmkp-jump-to-type-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j :' + "`bmkp-jump-to-type', but in another window." + (interactive + (let* ((completion-ignore-case t) + (type-cands (bmkp-types-alist)) + (icicle-unpropertize-completion-result-flag t) + (type (completing-read "Type of bookmark: " type-cands)) + (history (assoc-default type type-cands)) + (alist (if history + (funcall + (intern (format "bmkp-%s-alist-only" type))) + bookmark-alist)) + (bmk-name (bmkp-read-bookmark-for-type + type alist t + ;; PREDICATE if not a recognized type name. + (and (not history) + (bmkp-handler-pred (intern type))) + history))) + (list bmk-name (or (equal type "Region") current-prefix-arg)))) + (when (stringp bookmark) (error "Not a bookmark record (perhaps a bookmark name): `%s'" bookmark)) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +(defun bmkp-handler-pred (type) + "Return a bookmark predicate that tests bookmarks with handler TYPE. +More precisely, the predicate returns non-nil if TYPE is either the +bookmark's `handler' or `file-handler' entry value." + `(lambda (bmk) + (member ',type `(,(bookmark-prop-get bmk 'file-handler) ,(bookmark-get-handler bmk))))) + +;;;###autoload (autoload 'bmkp-autonamed-jump "bookmark+") +(defun bmkp-autonamed-jump (bookmark) ; `C-x j #' + "Jump to an autonamed bookmark. +This is a specialization of `bookmark-jump'." + (interactive + (let ((alist (bmkp-autonamed-alist-only))) + (list (bmkp-read-bookmark-for-type "autonamed" alist nil nil 'bmkp-autonamed-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-autonamed-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window)) + +;;;###autoload (autoload 'bmkp-autonamed-jump-other-window "bookmark+") +(defun bmkp-autonamed-jump-other-window (bookmark) ; `C-x 4 j # #' + "`bmkp-autonamed-jump', but in another window." + (interactive + (let ((alist (bmkp-autonamed-alist-only))) + (list (bmkp-read-bookmark-for-type "autonamed" alist t nil 'bmkp-autonamed-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-autonamed-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window)) + +;;;###autoload (autoload 'bmkp-autonamed-this-buffer-jump "bookmark+") +(defun bmkp-autonamed-this-buffer-jump (bookmark) ; `C-x j , #' + "Jump to an autonamed bookmark in the current buffer. +This is a specialization of `bookmark-jump'." + (interactive + (let ((alist (bmkp-autonamed-this-buffer-alist-only))) + (list (bmkp-read-bookmark-for-type "autonamed" alist nil nil 'bmkp-autonamed-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-autonamed-this-buffer-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window)) + +;;;###autoload (autoload 'bmkp-autonamed-this-buffer-jump-other-window "bookmark+") +(defun bmkp-autonamed-this-buffer-jump-other-window (bookmark) ; `C-x 4 j # .' + "`bmkp-autonamed-this-buffer-jump', but in another window." + (interactive + (let ((alist (bmkp-autonamed-this-buffer-alist-only))) + (list (bmkp-read-bookmark-for-type "autonamed" alist t nil 'bmkp-autonamed-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-autonamed-this-buffer-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window)) + +;;;###autoload (autoload 'bmkp-bookmark-list-jump "bookmark+") +(defun bmkp-bookmark-list-jump (bookmark &optional flip-use-region-p) ; `C-x j B' + "Jump to a bookmark-list bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-bookmark-list-alist-only))) + (list (bmkp-read-bookmark-for-type "bookmark-list" alist nil nil 'bmkp-bookmark-list-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-bookmark-list-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-desktop-jump "bookmark+") +(defun bmkp-desktop-jump (bookmark &optional flip-use-region-p) ; `C-x j K' + "Jump to a desktop bookmark. +If option `bmkp-desktop-jump-save-before-flag' is non-nil, and if the +current desktop was made current by jumping to a bookmark, then save +it before jumping to the next desktop. + +This command is a specialization of `bookmark-jump' - see that, in +particular for info about using a prefix argument." + (interactive + (let ((alist (bmkp-desktop-alist-only))) + (list (bmkp-read-bookmark-for-type "desktop" alist nil nil 'bmkp-desktop-history) + current-prefix-arg))) + (when bmkp-desktop-jump-save-before-flag (bmkp-desktop-save-as-last)) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-desktop-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p) + (setq bmkp-desktop-current-file (bookmark-prop-get bookmark 'desktop-file))) + +;;;###autoload (autoload 'bmkp-dired-jump "bookmark+") +(defun bmkp-dired-jump (bookmark &optional flip-use-region-p) ; `C-x j d', (`J' in Dired) + "Jump to a Dired bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-dired-alist-only))) + (list (bmkp-read-bookmark-for-type "Dired" alist nil nil 'bmkp-dired-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-dired-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-dired-jump-other-window "bookmark+") +(defun bmkp-dired-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j d' + "`bmkp-dired-jump', but in another window." + (interactive + (let ((alist (bmkp-dired-alist-only))) + (list (bmkp-read-bookmark-for-type "Dired" alist t nil 'bmkp-dired-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-dired-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-dired-this-dir-jump "bookmark+") +(defun bmkp-dired-this-dir-jump (bookmark &optional flip-use-region-p) ; `C-x j . d', (`C-j' in Dired) + "Jump to a Dired bookmark for the `default-directory'. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-dired-this-dir-alist-only))) + (list (bmkp-read-bookmark-for-type "Dired-for-this-dir " alist nil nil 'bmkp-dired-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-dired-this-dir-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-dired-this-dir-jump-other-window "bookmark+") +(defun bmkp-dired-this-dir-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j C-d' + "`bmkp-dired-this-dir-jump', but in another window." + (interactive + (let ((alist (bmkp-dired-this-dir-alist-only))) + (list (bmkp-read-bookmark-for-type "Dired-for-this-dir" alist t nil 'bmkp-dired-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-dired-this-dir-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +(when (fboundp 'bmkp-eww-alist-only) ; Emacs 25+ + + ;; ;;;###autoload (autoload 'bmkp-eww-jump "bookmark+") + (defun bmkp-eww-jump (bookmark &optional flip-use-region-p) ; `C-x j e' + "Jump to an EWW bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-eww-alist-only))) + (list (bmkp-read-bookmark-for-type "EWW" alist nil nil 'bmkp-eww-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-eww-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + + ;; ;;;###autoload (autoload 'bmkp-eww-jump-other-window "bookmark+") + (defun bmkp-eww-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j e' + "`bmkp-eww-jump', but in another window." + (interactive + (let ((alist (bmkp-eww-alist-only))) + (list (bmkp-read-bookmark-for-type "EWW" alist t nil 'bmkp-eww-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-eww-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + + ) + +;;;###autoload (autoload 'bmkp-file-jump "bookmark+") +(defun bmkp-file-jump (bookmark &optional flip-use-region-p) ; `C-x j f' + "Jump to a file or directory bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-file-alist-only))) + (list (bmkp-read-bookmark-for-type "file" alist nil nil 'bmkp-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-file-jump-other-window "bookmark+") +(defun bmkp-file-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j f' + "`bmkp-file-jump', but in another window." + (interactive + (let ((alist (bmkp-file-alist-only))) + (list (bmkp-read-bookmark-for-type "file" alist t nil 'bmkp-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-file-this-dir-jump "bookmark+") +(defun bmkp-file-this-dir-jump (bookmark &optional flip-use-region-p) ; `C-x j . f' + "Jump to a bookmark for a file or subdir in the `default-directory'. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-file-this-dir-alist-only))) + (list (bmkp-read-bookmark-for-type "file-in-this-dir" alist nil nil 'bmkp-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-file-this-dir-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-file-this-dir-jump-other-window "bookmark+") +(defun bmkp-file-this-dir-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j . f' + "`bmkp-file-this-dir-jump', but in another window." + (interactive + (let ((alist (bmkp-file-this-dir-alist-only))) + (list (bmkp-read-bookmark-for-type "file-in-this-dir" alist t nil 'bmkp-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-file-this-dir-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-gnus-jump "bookmark+") +(defun bmkp-gnus-jump (bookmark &optional flip-use-region-p) ; `C-x j g', (`j' in Gnus summary mode) + "Jump to a Gnus bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-gnus-alist-only))) + (list (bmkp-read-bookmark-for-type "Gnus" alist nil nil 'bmkp-gnus-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-gnus-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-gnus-jump-other-window "bookmark+") +(defun bmkp-gnus-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j g' + "`bmkp-gnus-jump', but in another window." + (interactive + (let ((alist (bmkp-gnus-alist-only))) + (list (bmkp-read-bookmark-for-type "Gnus" alist t nil 'bmkp-gnus-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-gnus-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-image-jump "bookmark+") +(defun bmkp-image-jump (bookmark &optional flip-use-region-p) ; `C-x j M-i' + "Jump to an image-file bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-image-alist-only))) + (list (bmkp-read-bookmark-for-type "image" alist nil nil 'bmkp-image-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-image-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-image-jump-other-window "bookmark+") +(defun bmkp-image-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x j M-i' + "`bmkp-image-jump', but in another window." + (interactive + (let ((alist (bmkp-image-alist-only))) + (list (bmkp-read-bookmark-for-type "image" alist t nil 'bmkp-image-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-image-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-info-jump "bookmark+") +(defun bmkp-info-jump (bookmark &optional flip-use-region-p) ; `C-x j i', (`j' in Info) + "Jump to an Info bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-info-alist-only))) + (list (bmkp-read-bookmark-for-type "Info" alist nil nil 'bmkp-info-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-info-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-info-jump-other-window "bookmark+") +(defun bmkp-info-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j i' + "`bmkp-info-jump', but in another window." + (interactive + (let ((alist (bmkp-info-alist-only))) + (list (bmkp-read-bookmark-for-type "Info" alist t nil 'bmkp-info-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-info-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-local-file-jump "bookmark+") +(defun bmkp-local-file-jump (bookmark &optional flip-use-region-p) ; `C-x j l' + "Jump to a local file or directory bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-local-file-alist-only))) + (list (bmkp-read-bookmark-for-type "local file" alist nil nil 'bmkp-local-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-local-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-local-file-jump-other-window "bookmark+") +(defun bmkp-local-file-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j l' + "`bmkp-local-file-jump', but in another window." + (interactive + (let ((alist (bmkp-local-file-alist-only))) + (list (bmkp-read-bookmark-for-type "local file" alist t nil 'bmkp-local-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-local-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-local-non-dir-file-jump "bookmark+") +(defun bmkp-local-non-dir-file-jump (bookmark &optional flip-use-region-p) ; Not bound + "Jump to a local nondirectory file bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-local-non-dir-file-alist-only))) + (list (bmkp-read-bookmark-for-type "local non-dir file" alist nil nil 'bmkp-local-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-local-non-dir-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-local-non-dir-file-jump-other-window "bookmark+") +(defun bmkp-local-non-dir-file-jump-other-window (bookmark &optional flip-use-region-p) ; Not bound + "`bmkp-local-non-dir-file-jump', but in another window." + (interactive + (let ((alist (bmkp-local-non-dir-file-alist-only))) + (list (bmkp-read-bookmark-for-type "local non-dir file" alist t nil 'bmkp-local-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-local-non-dir-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-man-jump "bookmark+") +(defun bmkp-man-jump (bookmark &optional flip-use-region-p) ; `C-x j m', (`j' in Man) + "Jump to a `man'-page bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-man-alist-only))) + (list (bmkp-read-bookmark-for-type "`man'" alist nil nil 'bmkp-man-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-man-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-man-jump-other-window "bookmark+") +(defun bmkp-man-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j m' + "`bmkp-man-jump', but in another window." + (interactive + (let ((alist (bmkp-man-alist-only))) + (list (bmkp-read-bookmark-for-type "`man'" alist t nil 'bmkp-man-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-man-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-non-dir-file-jump "bookmark+") +(defun bmkp-non-dir-file-jump (bookmark &optional flip-use-region-p) ; Not bound + "Jump to a nondirectory file bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-non-dir-file-alist-only))) + (list (bmkp-read-bookmark-for-type "non-dir file" alist nil nil 'bmkp-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-non-dir-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-non-dir-file-jump-other-window "bookmark+") +(defun bmkp-non-dir-file-jump-other-window (bookmark &optional flip-use-region-p) ; Not bound + "`bmkp-non-dir-file-jump', but in another window." + (interactive + (let ((alist (bmkp-non-dir-file-alist-only))) + (list (bmkp-read-bookmark-for-type "non-dir file" alist t nil 'bmkp-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-non-dir-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-non-file-jump "bookmark+") +(defun bmkp-non-file-jump (bookmark &optional flip-use-region-p) ; `C-x j b', (`j' in Buffer Menu) + "Jump to a non-file (buffer) bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-non-file-alist-only))) + (list (bmkp-read-bookmark-for-type "non-file (buffer)" alist nil nil 'bmkp-non-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-non-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-non-file-jump-other-window "bookmark+") +(defun bmkp-non-file-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j b' + "`bmkp-non-file-jump', but in another window." + (interactive + (let ((alist (bmkp-non-file-alist-only))) + (list (bmkp-read-bookmark-for-type "non-file (buffer)" alist t nil 'bmkp-non-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-non-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-region-jump "bookmark+") +(defun bmkp-region-jump (bookmark) ; `C-x j r' + "Jump to a region bookmark. Select the region. +This is a specialization of `bookmark-jump', but without a prefix arg. +BOOKMARK is a bookmark name or a bookmark record." + (interactive (list (bmkp-read-bookmark-for-type "region" (bmkp-region-alist-only) nil nil + 'bmkp-region-history))) + (let ((bmkp-use-region t)) (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window))) + +;;;###autoload (autoload 'bmkp-region-jump-other-window "bookmark+") +(defun bmkp-region-jump-other-window (bookmark) ; `C-x 4 j r' + "`bmkp-region-jump', but in another window." + (interactive (list (bmkp-read-bookmark-for-type "region" (bmkp-region-alist-only) t nil + 'bmkp-region-history))) + (let ((bmkp-use-region t)) (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window))) + +;; This command accepts no argument. It calls another command interactively, which reads the bookmark name. +;; +;;;###autoload (autoload 'bmkp-region-jump-narrow-indirect-other-window "bookmark+") +(defun bmkp-region-jump-narrow-indirect-other-window () + "Jump to a region bookmark and narrow to it in a cloned indirect buffer. +You are prompted for the region bookmark. + +The region is selected as usual, in the bookmarked file/buffer. A +separate window is opened on the region text, for the cloned indirect +buffer. + +You need library `narrow-indirect.el' to use this command." + (interactive) + (unless (require 'narrow-indirect nil t) + (error "You need library `narrow-indirect.el' for this command")) + (let ((bmkp-handle-region-function 'bmkp-handle-region+narrow-indirect)) + (call-interactively + (if (and (boundp 'icicle-mode) icicle-mode) ; Icicles + #'icicle-bookmark-region-other-window + #'bmkp-region-jump-other-window)))) + +(defun bmkp-handle-region+narrow-indirect (bookmark) + "`bmkp-handle-region-default', then narrow to region in cloned buffer." + (let ((bmkp-handle-region-function 'bmkp-handle-region-default)) + (bookmark-handle-bookmark bookmark)) + (if (get major-mode 'no-clone-indirect) ; e.g., `Info-mode' + (message "Cannot indirectly clone a buffer in `%s' mode" major-mode) + (ni-narrow-to-region-indirect-other-window (region-beginning) (region-end) (point)))) + +;;;###autoload (autoload 'bmkp-remote-file-jump "bookmark+") +(defun bmkp-remote-file-jump (bookmark &optional flip-use-region-p) ; `C-x j n' + "Jump to a remote file or directory bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-remote-file-alist-only))) + (list (bmkp-read-bookmark-for-type "remote file" alist nil nil 'bmkp-remote-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-remote-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-remote-file-jump-other-window "bookmark+") +(defun bmkp-remote-file-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j n' + "`bmkp-remote-file-jump', but in another window." + (interactive + (let ((alist (bmkp-remote-file-alist-only))) + (list (bmkp-read-bookmark-for-type "remote file" alist t nil 'bmkp-remote-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-remote-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-remote-non-dir-file-jump "bookmark+") +(defun bmkp-remote-non-dir-file-jump (bookmark &optional flip-use-region-p) ; Not bound + "Jump to a remote nondirectory file bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-remote-non-dir-file-alist-only))) + (list (bmkp-read-bookmark-for-type "remote non-dir file" alist nil nil 'bmkp-remote-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-remote-non-dir-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-remote-non-dir-file-jump-other-window "bookmark+") +(defun bmkp-remote-non-dir-file-jump-other-window (bookmark &optional flip-use-region-p) ; Not bound + "`bmkp-remote-non-dir-file-jump', but in another window." + (interactive + (let ((alist (bmkp-remote-non-dir-file-alist-only))) + (list (bmkp-read-bookmark-for-type "remote non-dir file" alist t nil 'bmkp-remote-file-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-remote-non-dir-file-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-specific-buffers-jump "bookmark+") +(defun bmkp-specific-buffers-jump (buffers bookmark &optional flip-use-region-p) ; `C-x j = b' + "Jump to a bookmark for a buffer in list BUFFERS. +Interactively, read buffer names and bookmark name, with completion. + +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let* ((buffs (bmkp-read-buffers)) + (alist (bmkp-specific-buffers-alist-only buffs))) + (list buffs (bmkp-read-bookmark-for-type "specific-buffers" alist nil nil 'specific-buffers-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-specific-buffers-alist-only buffers)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-specific-buffers-jump-other-window "bookmark+") +(defun bmkp-specific-buffers-jump-other-window (buffers bookmark + &optional flip-use-region-p) ; `C-x 4 j = b' + "`bmkp-specific-buffers-jump', but in another window." + (interactive + (let* ((buffs (bmkp-read-buffers)) + (alist (bmkp-specific-buffers-alist-only buffs))) + (list buffs (bmkp-read-bookmark-for-type "specific-buffers" alist t nil 'specific-buffers-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-specific-buffers-alist-only buffers)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-specific-files-jump "bookmark+") +(defun bmkp-specific-files-jump (files bookmark &optional flip-use-region-p) ; `C-x j = f' + "Jump to a bookmark for a file in list FILES. +Interactively, read file names and bookmark name, with completion. + +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let* ((fils (bmkp-read-files)) + (alist (bmkp-specific-files-alist-only fils))) + (list fils + (bmkp-read-bookmark-for-type "specific-files" alist nil nil 'specific-files-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-specific-files-alist-only files)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-specific-files-jump-other-window "bookmark+") +(defun bmkp-specific-files-jump-other-window (files bookmark + &optional flip-use-region-p) ; `C-x 4 j = f' + "`bmkp-specific-files-jump', but in another window." + (interactive + (let* ((fils (bmkp-read-files)) + (alist (bmkp-specific-files-alist-only fils))) + (list fils + (bmkp-read-bookmark-for-type "specific-files" alist t nil 'specific-files-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-specific-files-alist-only files)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-temporary-jump "bookmark+") +(defun bmkp-temporary-jump (bookmark) ; `C-x j x' + "Jump to a temporary bookmark. +This is a specialization of `bookmark-jump', but without a prefix arg." + (interactive (list (bmkp-read-bookmark-for-type "temporary" (bmkp-temporary-alist-only) nil nil + 'bmkp-temporary-history))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-temporary-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window)) + +;;;###autoload (autoload 'bmkp-temporary-jump-other-window "bookmark+") +(defun bmkp-temporary-jump-other-window (bookmark) ; `C-x 4 j x' + "`bmkp-temporary-jump', but in another window." + (interactive (list (bmkp-read-bookmark-for-type "temporary" (bmkp-temporary-alist-only) t nil + 'bmkp-temporary-history))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-temporary-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window)) + +;;;###autoload (autoload 'bmkp-this-buffer-jump "bookmark+") +(defun bmkp-this-buffer-jump (bookmark &optional flip-use-region-p) ; `C-x j , ,' + "Jump to a bookmark for the current buffer. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-this-buffer-alist-only))) + (unless alist (error "No bookmarks for this buffer")) + (list (bookmark-completing-read "Jump to bookmark for this buffer" + (bmkp-default-bookmark-name alist) alist) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-this-buffer-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-this-buffer-jump-other-window "bookmark+") +(defun bmkp-this-buffer-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j , ,' + "`bmkp-this-buffer-jump', but in another window." + (interactive + (let ((alist (bmkp-this-buffer-alist-only))) + (unless alist (error "No bookmarks for this buffer")) + (list (bookmark-completing-read "Jump to bookmark for this buffer in another window" + (bmkp-default-bookmark-name alist) alist) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-this-buffer-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;; ;;;###autoload +;;; (defun bmkp-this-file-jump (bookmark-name &optional flip-use-region-p) +;;; "Jump to a bookmark for the current file (absolute file name). +;;; This is a specialization of `bookmark-jump' - see that, in particular +;;; for info about using a prefix argument." +;;; (interactive +;;; (progn (unless (or (buffer-file-name) (and (eq major-mode 'dired-mode) +;;; (if (consp dired-directory) +;;; (car dired-directory) +;;; dired-directory))) +;;; (error "This buffer is not associated with a file")) +;;; (let ((alist (bmkp-this-file-alist-only))) +;;; (unless alist (error "No bookmarks for this file")) +;;; (list (bookmark-completing-read "Jump to bookmark for this file" +;;; (bmkp-default-bookmark-name alist) alist) +;;; current-prefix-arg)))) +;;; (bmkp-jump-1 bookmark-name 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;; ;;;###autoload +;;; (defun bmkp-this-file-jump-other-window (bookmark-name &optional flip-use-region-p) +;;; "`bmkp-this-file-jump', but in another window." +;;; (interactive +;;; (progn (unless (or (buffer-file-name) (and (eq major-mode 'dired-mode) +;;; (if (consp dired-directory) +;;; (car dired-directory) +;;; dired-directory))) +;;; (error "This buffer is not associated with a file")) +;;; (let ((alist (bmkp-this-file-alist-only))) +;;; (unless alist (error "No bookmarks for this file")) +;;; (list (bookmark-completing-read "Jump to bookmark for this file in another window" +;;; (bmkp-default-bookmark-name alist) alist) +;;; current-prefix-arg)))) +;;; (bmkp-jump-1 bookmark-name 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-variable-list-jump "bookmark+") +(defun bmkp-variable-list-jump (bookmark) ; `C-x j v' + "Jump to a variable-list bookmark. +This is a specialization of `bookmark-jump'." + (interactive + (let ((alist (bmkp-variable-list-alist-only))) + (list (bmkp-read-bookmark-for-type "variable-list" alist nil nil 'bmkp-variable-list-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-variable-list-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window)) + +;;;###autoload (autoload 'bmkp-url-jump "bookmark+") +(defun bmkp-url-jump (bookmark &optional flip-use-region-p) ; `C-x j u' + "Jump to a URL bookmark. +It can be an EWW bookmark, a W3M bookmark, or a browse-URL bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-url-alist-only))) + (list (bmkp-read-bookmark-for-type "URL" alist nil nil 'bmkp-url-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-url-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-url-jump-other-window "bookmark+") +(defun bmkp-url-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j u' + "`bmkp-url-jump', but in another window." + (interactive + (let ((alist (bmkp-url-alist-only))) + (list (bmkp-read-bookmark-for-type "URL" alist t nil 'bmkp-url-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-url-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-w32-browser-jump "bookmark+") +(defun bmkp-w32-browser-jump (bookmark) ; Not bound + "Jump to a bookmark whose handler applies `w32-browser' to its file. +This is a specialization of `bookmark-jump'." + (interactive + (list (bmkp-read-bookmark-for-type "w32-browser" bookmark-alist nil + ;; Use a predicate, since `w32-browser' is a handler, not a type name. + (bmkp-handler-pred 'w32-browser) + 'bmkp-w32-browser-history))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window)) + +;;;###autoload (autoload 'bmkp-w3m-jump "bookmark+") +(defun bmkp-w3m-jump (bookmark &optional flip-use-region-p) ; `C-x j w', (`j' in W3M) + "Jump to a W3M bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-w3m-alist-only))) + (list (bmkp-read-bookmark-for-type "W3M" alist nil nil 'bmkp-w3m-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-w3m-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-w3m-jump-other-window "bookmark+") +(defun bmkp-w3m-jump-other-window (bookmark &optional flip-use-region-p) ; `C-x 4 j w' + "`bmkp-w3m-jump', but in another window." + (interactive + (let ((alist (bmkp-w3m-alist-only))) + (list (bmkp-read-bookmark-for-type "W3M" alist t nil 'bmkp-w3m-history) + current-prefix-arg))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-w3m-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-all-tags-jump "bookmark+") +(defun bmkp-all-tags-jump (tags bookmark) ; `C-x j t *' + "Jump to a BOOKMARK that has all of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. +If you specify no tags, then every bookmark that has some tags is a +candidate. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-all-tags-alist-only tgs))) + (unless alist (error "No bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-all-tags-jump-other-window "bookmark+") +(defun bmkp-all-tags-jump-other-window (tags bookmark) ; `C-x 4 j t *' + "`bmkp-all-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-all-tags-alist-only tgs))) + (unless alist (error "No bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-all-tags-regexp-jump "bookmark+") +(defun bmkp-all-tags-regexp-jump (regexp bookmark) ; `C-x j t % *' + "Jump to a BOOKMARK that has each tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for all tags: ")) + (alist (bmkp-all-tags-regexp-alist-only rgx))) + (unless alist (error "No bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-all-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-all-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t % *' + "`bmkp-all-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for all tags: ")) + (alist (bmkp-all-tags-regexp-alist-only rgx))) + (unless alist (error "No bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-some-tags-jump "bookmark+") +(defun bmkp-some-tags-jump (tags bookmark) ; `C-x j t +' + "Jump to a BOOKMARK that has at least one of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-some-tags-jump-other-window "bookmark+") +(defun bmkp-some-tags-jump-other-window (tags bookmark) ; `C-x 4 j t +' + "`bmkp-some-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-some-tags-regexp-jump "bookmark+") +(defun bmkp-some-tags-regexp-jump (regexp bookmark) ; `C-x j t % +' + "Jump to a BOOKMARK that has a tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-some-tags-regexp-alist-only rgx))) + (unless alist (error "No bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-some-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-some-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t % +' + "`bmkp-some-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-some-tags-regexp-alist-only rgx))) + (unless alist (error "No bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-all-tags-jump "bookmark+") +(defun bmkp-file-all-tags-jump (tags bookmark) ; `C-x j t f *' + "Jump to a file or directory BOOKMARK that has all of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. +If you specify no tags, then every bookmark that has some tags is a +candidate. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-all-tags-alist-only tgs))) + (unless alist (error "No file or dir bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-all-tags-jump-other-window "bookmark+") +(defun bmkp-file-all-tags-jump-other-window (tags bookmark) ; `C-x 4 j t f *' + "`bmkp-file-all-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-all-tags-alist-only tgs))) + (unless alist (error "No file or dir bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-all-tags-regexp-jump "bookmark+") +(defun bmkp-file-all-tags-regexp-jump (regexp bookmark) ; `C-x j t f % *' + "Jump to a file or directory BOOKMARK that has each tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-all-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-all-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-file-all-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t f % *' + "`bmkp-file-all-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-all-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-some-tags-jump "bookmark+") +(defun bmkp-file-some-tags-jump (tags bookmark) ; `C-x j t f +' + "Jump to a file or directory BOOKMARK that has at least one of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No file or dir bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-some-tags-jump-other-window "bookmark+") +(defun bmkp-file-some-tags-jump-other-window (tags bookmark) ; `C-x 4 j t f +' + "`bmkp-file-some-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No file or dir bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-some-tags-regexp-jump "bookmark+") +(defun bmkp-file-some-tags-regexp-jump (regexp bookmark) ; `C-x j t f % +' + "Jump to a file or directory BOOKMARK that has a tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-some-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-some-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-file-some-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t f % +' + "`bmkp-file-some-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-some-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-all-tags-jump "bookmark+") +(defun bmkp-file-this-dir-all-tags-jump (tags bookmark) ; `C-x j t . *' + "Jump to a file BOOKMARK in this dir that has all of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. +If you specify no tags, then every bookmark that has some tags is a +candidate. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-this-dir-all-tags-alist-only tgs))) + (unless alist (error "No file or dir bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-all-tags-jump-other-window "bookmark+") +(defun bmkp-file-this-dir-all-tags-jump-other-window (tags bookmark) ; `C-x 4 j t . *' + "`bmkp-file-this-dir-all-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-this-dir-all-tags-alist-only tgs))) + (unless alist (error "No file or dir bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-all-tags-regexp-jump "bookmark+") +(defun bmkp-file-this-dir-all-tags-regexp-jump (regexp bookmark) ; `C-x j t . % *' + "Jump to a file BOOKMARK in this dir that has each tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-this-dir-all-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-all-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-file-this-dir-all-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t . % *' + "`bmkp-file-this-dir-all-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-this-dir-all-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-some-tags-jump "bookmark+") +(defun bmkp-file-this-dir-some-tags-jump (tags bookmark) ; `C-x j t . +' + "Jump to a file BOOKMARK in this dir that has at least one of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-this-dir-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No file or dir bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-some-tags-jump-other-window "bookmark+") +(defun bmkp-file-this-dir-some-tags-jump-other-window (tags bookmark) ; `C-x 4 j t . +' + "`bmkp-file-this-dir-some-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-file-this-dir-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No file or dir bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-some-tags-regexp-jump "bookmark+") +(defun bmkp-file-this-dir-some-tags-regexp-jump (regexp bookmark) ; `C-x j t . % +' + "Jump to a file BOOKMARK in this dir that has a tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-this-dir-some-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-file-this-dir-some-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-file-this-dir-some-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t . % +' + "`bmkp-file-this-dir-some-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-file-this-dir-some-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-jump "bookmark+") +(defun bmkp-autofile-jump (bookmark) ; `C-x j a' + "Jump to an autofile bookmark. +This is a specialization of `bookmark-jump'." + (interactive + (let ((alist (bmkp-autofile-alist-only))) + (list (bmkp-read-bookmark-for-type "autofile" alist nil nil 'bmkp-autofile-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-autofile-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp--pop-to-buffer-same-window)) + +;;;###autoload (autoload 'bmkp-autofile-jump-other-window "bookmark+") +(defun bmkp-autofile-jump-other-window (bookmark) ; `C-x 4 j a' + "`bmkp-autofile-jump' but in another window." + (interactive + (let ((alist (bmkp-autofile-alist-only))) + (list (bmkp-read-bookmark-for-type "autofile" alist t nil 'bmkp-autofile-history)))) + (when (stringp bookmark) + (setq bookmark (bmkp-get-bookmark-in-alist bookmark 'NOERROR (bmkp-autofile-alist-only)))) + (bmkp-jump-1 bookmark 'bmkp-select-buffer-other-window)) + +;;;###autoload (autoload 'bmkp-autofile-all-tags-jump "bookmark+") +(defun bmkp-autofile-all-tags-jump (tags bookmark) ; `C-x j t a *' + "Jump to an autofile BOOKMARK in this dir that has all of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. +If you specify no tags, then every bookmark that has some tags is a +candidate. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-autofile-all-tags-alist-only tgs))) + (unless alist (error "No file or dir bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-all-tags-jump-other-window "bookmark+") +(defun bmkp-autofile-all-tags-jump-other-window (tags bookmark) ; `C-x 4 j t a *' + "`bmkp-autofile-all-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-autofile-all-tags-alist-only tgs))) + (unless alist (error "No file or dir bookmarks have all of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-all-tags-regexp-jump "bookmark+") +(defun bmkp-autofile-all-tags-regexp-jump (regexp bookmark) ; `C-x j t a % *' + "Jump to an autofile BOOKMARK in this dir that has each tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-autofile-all-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-all-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-autofile-all-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t a % *' + "`bmkp-autofile-all-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-autofile-all-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-some-tags-jump "bookmark+") +(defun bmkp-autofile-some-tags-jump (tags bookmark) ; `C-x j t a +' + "Jump to an autofile BOOKMARK in this dir that has at least one of the TAGS. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter the bookmark name and each tag. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-autofile-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No file or dir bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-some-tags-jump-other-window "bookmark+") +(defun bmkp-autofile-some-tags-jump-other-window (tags bookmark) ; `C-x 4 j t a +' + "`bmkp-autofile-some-tags-jump', but in another window." + (interactive + (let* ((tgs (bmkp-read-tags-completing nil nil current-prefix-arg)) + (alist (bmkp-autofile-some-tags-alist-only tgs))) + (unless tgs (error "You did not specify any tags")) + (unless alist (error "No file or dir bookmarks have any of the specified tags")) + (list tgs (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-some-tags-regexp-jump "bookmark+") +(defun bmkp-autofile-some-tags-regexp-jump (regexp bookmark) ; `C-x j t a % +' + "Jump to an autofile BOOKMARK in this dir that has a tag matching REGEXP. +You are prompted for the REGEXP. +Then you are prompted for the BOOKMARK (with completion)." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-autofile-some-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump bookmark)) + +;;;###autoload (autoload 'bmkp-autofile-some-tags-regexp-jump-other-window "bookmark+") +(defun bmkp-autofile-some-tags-regexp-jump-other-window (regexp bookmark) ; `C-x 4 j t a % +' + "`bmkp-autofile-some-tags-regexp-jump', but in another window." + (interactive + (let* ((rgx (bmkp-read-regexp "Regexp for tags: ")) + (alist (bmkp-autofile-some-tags-regexp-alist-only rgx))) + (unless alist (error "No file or dir bookmarks have tags that match `%s'" rgx)) + (list rgx (bookmark-completing-read "File bookmark" (bmkp-default-bookmark-name alist) alist)))) + (bookmark-jump-other-window bookmark)) + +(defun bmkp-find-file (&optional file create-autofile-p must-exist-p msg-p) ; `C-x j C-f' + "Visit a file or directory, respecting any associated autofile handlers. +You are prompted for the file or directory name, FILE. + +If FILE matches an entry in `bmkp-default-handlers-for-file-types' +then use the associated default handler to access the file. +Otherwise, just use `find-file'. + +With a prefix arg, create an autofile bookmark if FILE does not +already have one. + +Non-interactively: +* Non-nil MUST-EXIST-P means raise an error if FILE has no autofile + bookmark. +* Non-nil MSG-P means display a status message." + (interactive "i\nP\ni\np") + (let* ((use-file-dialog nil) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (fil (or file (read-file-name "Find file: " nil nil t))) + (dir-to-use (if (file-name-absolute-p fil) + (file-name-directory fil) + default-directory)) + (bmk (bmkp-get-autofile-bookmark fil))) + (if bmk + (bookmark-jump bmk) + (when must-exist-p (error "File `%s' is not an autofile (no bookmark)" fil)) + (when create-autofile-p ; Create a new bookmark. + (bmkp-file-target-set (expand-file-name fil dir-to-use) t nil 'NO-OVERWRITE msg-p) + (when msg-p (message "Autofile bookmark set for `%s'" fil))) + (let ((default-handler (condition-case nil (bmkp-default-handler-for-file fil) (error nil)))) + (if default-handler (funcall default-handler fil) (find-file fil 'WILDCARDS)))))) + +(defun bmkp-find-file-other-window (&optional file create-autofile-p must-exist-p msg-p) ; `C-x 4 j C-f' + "`bmkp-find-file', but in another window." + (interactive "i\nP\ni\np") + (let* ((use-file-dialog nil) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (fil (or file (read-file-name "Find file: " nil nil t))) + (dir-to-use (if (file-name-absolute-p fil) + (file-name-directory fil) + default-directory)) + (bmk (bmkp-get-autofile-bookmark fil dir-to-use))) + (if bmk + (bookmark-jump-other-window bmk) + (when must-exist-p (error "File `%s' is not an autofile (no bookmark)" fil)) + (when create-autofile-p ; Create a new bookmark. + (bmkp-file-target-set (expand-file-name fil dir-to-use) t nil 'NO-OVERWRITE msg-p) + (when msg-p (message "Autofile bookmark created for `%s'" fil))) + (let ((default-handler (condition-case nil (bmkp-default-handler-for-file fil) (error nil)))) + (if default-handler (funcall default-handler fil) (find-file-other-window fil 'WILDCARDS)))))) + + +;;; We could allow these even for Emacs 20 for Icicles users, +;;; but the predicate would have no effect when not in Icicle mode. So don't bother with Emacs 20. + +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-all-tags (tags &optional file) ; `C-x j t C-f *' + "Visit a file or directory that has all of the TAGS. +You are prompted first for the tags. Hit `RET' to enter each tag, +then hit `RET' again after the last tag. You can use completion to +enter each tag. This completion is lax: you are not limited to +existing tags. + +You are then prompted for the file name. This is read using +`read-file-name', so you can browse up and down the file hierarchy. +The completion candidates are file names, not bookmark names. +However, only files that are bookmarked as autofiles are candidates. + +If you specify no tags, then every file that has some tags is a +candidate. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive (list (bmkp-read-tags-completing nil nil current-prefix-arg))) + (lexical-let* ((tgs tags) + (use-file-dialog nil) + (pred + (lambda (ff) + (lexical-let* ((bmk (bmkp-get-autofile-bookmark ff)) + (btgs (and bmk (bmkp-get-tags bmk)))) + (and btgs (bmkp-every (lambda (tag) (bmkp-has-tag-p bmk tag)) tgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (when bmk (bookmark-jump bmk))))) + +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-all-tags-other-window (tags &optional file) ; `C-x 4 j t C-f *' + "`bmkp-find-file-all-tags', but in another window." + (interactive (list (bmkp-read-tags-completing nil nil current-prefix-arg))) + (lexical-let* ((tgs tags) + (use-file-dialog nil) + (pred + (lambda (ff) + (lexical-let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-every (lambda (tag) (bmkp-has-tag-p bk tag)) tgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump-other-window bmk)))) + +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-all-tags-regexp (regexp &optional file) ; `C-x j t C-f % *' + "Visit a file or directory that has each tag matching REGEXP. +You are prompted for the REGEXP." + (interactive (list (bmkp-read-regexp "Regexp for tags: "))) + (lexical-let* ((rg regexp) + (use-file-dialog nil) + (pred + (lambda (ff) + (let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-every (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + btgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump bmk)))) + +;;;###autoload (autoload 'bmkp-find-file-all-tags-regexp-other-window "bookmark+") +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-all-tags-regexp-other-window (regexp &optional file) ; `C-x 4 j t C-f % *' + "`bmkp-find-file-all-tags-regexp', but in another window." + (interactive (list (bmkp-read-regexp "Regexp for tags: "))) + (lexical-let* ((rg regexp) + (use-file-dialog nil) + (pred + (lambda (ff) + (let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-every (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + btgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump-other-window bmk)))) + +;;;###autoload (autoload 'bmkp-find-file-some-tags "bookmark+") +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-some-tags (tags &optional file) ; `C-x j t C-f +' + "Visit a file or directory that has at least one of the TAGS. +You are prompted first for the tags. Hit `RET' to enter each tag, +then hit `RET' again after the last tag. You can use completion to +enter each tag. This completion is lax: you are not limited to +existing tags. + +You are then prompted for the file name. This is read using +`read-file-name', so you can browse up and down the file hierarchy. +The completion candidates are file names, not bookmark names. +However, only files that are bookmarked as autofiles are candidates. + +By default, the tag choices for completion are NOT refreshed, to save +time. Use a prefix argument if you want to refresh them." + (interactive (list (bmkp-read-tags-completing nil nil current-prefix-arg))) + (lexical-let* ((tgs tags) + (use-file-dialog nil) + (pred + (lambda (ff) + (lexical-let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-some (lambda (tag) (bmkp-has-tag-p bk tag)) tgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump bmk)))) + +;;;###autoload (autoload 'bmkp-find-file-some-tags-other-window "bookmark+") +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-some-tags-other-window (tags &optional file) ; `C-x 4 j t C-f +' + "`bmkp-find-file-some-tags', but in another window." + (interactive (list (bmkp-read-tags-completing nil nil current-prefix-arg))) + (lexical-let* ((tgs tags) + (use-file-dialog nil) + (pred + (lambda (ff) + (lexical-let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-some (lambda (tag) (bmkp-has-tag-p bk tag)) tgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump-other-window bmk)))) + +;;;###autoload (autoload 'bmkp-find-file-some-tags-regexp "bookmark+") +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-some-tags-regexp (regexp &optional file) ; `C-x j t C-f % +' + "Visit a file or directory that has a tag matching REGEXP. +You are prompted for the REGEXP." + (interactive (list (bmkp-read-regexp "Regexp for tags: "))) + (lexical-let* ((rg regexp) + (use-file-dialog nil) + (pred + (lambda (ff) + (let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-some (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + btgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump bmk)))) + +;;;###autoload (autoload 'bmkp-find-file-some-tags-regexp-other-window "bookmark+") +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (defun bmkp-find-file-some-tags-regexp-other-window (regexp &optional file) ; `C-x 4 j t C-f % +' + "`bmkp-find-file-some-tags-regexp', but in another window." + (interactive (list (bmkp-read-regexp "Regexp for tags: "))) + (lexical-let* ((rg regexp) + (use-file-dialog nil) + (pred + (lambda (ff) + (let* ((bk (bmkp-get-autofile-bookmark ff)) + (btgs (and bk (bmkp-get-tags bk)))) + (and btgs (bmkp-some (lambda (tag) (bmkp-string-match-p rg (bmkp-tag-name tag))) + btgs))))) + (icicle-unpropertize-completion-result-flag t) ; For `read-file-name'. + (icicle-must-pass-after-match-predicate pred) + (fil (or (and file (funcall pred file) file) + (read-file-name + "Find file: " nil nil t nil + (and (or (not (boundp 'icicle-mode)) + (not icicle-mode)) + pred)))) + (bmk (bmkp-get-autofile-bookmark fil))) + (bookmark-jump-other-window bmk)))) + +;;;###autoload (autoload 'bmkp-jump-in-navlist "bookmark+") +(defun bmkp-jump-in-navlist (bookmark-name &optional flip-use-region-p) ; `C-x j N' + "Jump to a bookmark, choosing from those in the navigation list." + (interactive + (progn (unless bmkp-nav-alist + (bookmark-maybe-load-default-file) + (setq bmkp-nav-alist bookmark-alist) + (unless bmkp-nav-alist (error "No bookmarks")) + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist)) + (message "Bookmark navigation list is now the global bookmark list") (sit-for 2)) + (let ((bookmark-alist bmkp-nav-alist)) + (list (bookmark-completing-read "Jump to bookmark" (bmkp-default-bookmark-name)) + current-prefix-arg)))) + (bmkp-jump-1 bookmark-name 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-jump-in-navlist-other-window "bookmark+") +(defun bmkp-jump-in-navlist-other-window (bookmark-name &optional flip-use-region-p) ; `C-x 4 j N' + "Same as `bmkp-jump-in-navlist', but use another window." + (interactive + (progn (unless bmkp-nav-alist + (bookmark-maybe-load-default-file) + (setq bmkp-nav-alist bookmark-alist) + (unless bmkp-nav-alist (error "No bookmarks")) + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist)) + (message "Bookmark navigation list is now the global bookmark list") (sit-for 2)) + (let ((bookmark-alist bmkp-nav-alist)) + (list (bookmark-completing-read "Jump to bookmark (in another window)" + (bmkp-default-bookmark-name)) + current-prefix-arg)))) + (bmkp-jump-1 bookmark-name 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-cycle "bookmark+") +(defun bmkp-cycle (increment &optional other-window startoverp) + "Cycle through bookmarks in the navlist by INCREMENT (default: 1). +Positive INCREMENT cycles forward. Negative INCREMENT cycles backward. +Interactively, the prefix arg determines INCREMENT: + Plain `C-u': 1 + otherwise: the numeric prefix arg value + +Plain `C-u' also means start over at first bookmark. + +You can set the navigation list using commands + `bmkp-choose-navlist-from-bookmark-list' and + `bmkp-choose-navlist-of-type'. + +You can cycle among bookmarks in the current buffer using + `bmkp-cycle-this-buffer' and + `bmkp-cycle-this-buffer-other-window.' + +In Lisp code: + Non-nil OTHER-WINDOW means jump to the bookmark in another window. + Non-nil STARTOVERP means reset `bmkp-current-nav-bookmark' to the + first bookmark in the navlist." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) nil startovr))) + (unless bmkp-nav-alist + (bookmark-maybe-load-default-file) + (when (and bookmark-alist (y-or-n-p "No navigation list. Use whole bookmark list? ")) + (setq bmkp-nav-alist bookmark-alist) + (message "Navigation list is now the global bookmark list") (sit-for 2)) + (unless bmkp-nav-alist (error "No bookmarks in navigation list")) + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist))) + (unless (and bmkp-current-nav-bookmark (not startoverp) + (bmkp-get-bookmark bmkp-current-nav-bookmark 'NOERROR)) + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist))) + (if (bmkp-cycle-1 increment other-window startoverp) + (unless (or (bmkp-sequence-bookmark-p bmkp-current-nav-bookmark) + (bmkp-function-bookmark-p bmkp-current-nav-bookmark)) + (message "Position: %9d, Bookmark: `%s'" + (point) (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark))) + (message "Invalid bookmark: `%s'" (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark)))) + +;;;###autoload (autoload 'bmkp-cycle-other-window "bookmark+") +(defun bmkp-cycle-other-window (increment &optional startoverp) + "Same as `bmkp-cycle' but uses another window." + (interactive "p") + (bmkp-cycle increment 'OTHER-WINDOW startoverp)) + +;;;###autoload (autoload 'bmkp-cycle-this-file/buffer "bookmark+") +(defun bmkp-cycle-this-file/buffer (increment &optional other-window startoverp) + "Cycle through bookmarks for this file/buffer by INCREMENT (default: 1). +If visiting a file, this is `bmkp-cycle-this-file'. +Otherwise, this is `bmkp-cycle-this-buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) nil startovr))) + (if (buffer-file-name) + (bmkp-cycle-this-file increment other-window startoverp) + (bmkp-cycle-this-buffer increment other-window startoverp))) + +;;;###autoload (autoload 'bmkp-cycle-this-file/buffer-other-window "bookmark+") +(defun bmkp-cycle-this-file/buffer-other-window (increment &optional startoverp) + "Same as `bmkp-cycle-this-file/buffer' but use other window." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-file/buffer increment 'OTHER-WINDOW startoverp)) + +;;;###autoload (autoload 'bmkp-cycle-this-file "bookmark+") +(defun bmkp-cycle-this-file (increment &optional other-window startoverp) + "Cycle through bookmarks for this file by INCREMENT (default: 1). +Positive INCREMENT cycles forward. Negative INCREMENT cycles backward. +Interactively, the prefix arg determines INCREMENT: + Plain `C-u': 1 + otherwise: the numeric prefix arg value + +Plain `C-u' also means start over at first bookmark. + +You can cycle among bookmarks beyond the current file using +`bmkp-cycle' and `bmkp-cycle-other-window.' + +You can set your preferred sort order for this-file bookmarks by +customizing option `bmkp-this-file/buffer-cycle-sort-comparer'. + +To change the sort order without customizing, you can use \ +`\\[bmkp-this-file-bmenu-list]' to +show the `*Bookmark List*' with only this file's bookmarks, sort +them there, and use `\\[bmkp-choose-navlist-from-bookmark-list]', choosing \ +`CURRENT *Bookmark List*' as +the navigation list. + +Then you can cycle the bookmarks using `bmkp-cycle' +\(`\\[bmkp-next-bookmark-repeat]' etc.), instead of `bmkp-cycle-this-file'. + +In Lisp code: + Non-nil OTHER-WINDOW means jump to the bookmark in another window. + Non-nil STARTOVERP means reset `bmkp-current-nav-bookmark' to the + first bookmark in the navlist." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) nil startovr))) + (bookmark-maybe-load-default-file) + (let ((bmkp-sort-comparer bmkp-this-file/buffer-cycle-sort-comparer)) + (setq bmkp-nav-alist (bmkp-sort-omit (bmkp-this-file-alist-only)))) + (unless bmkp-nav-alist (error "No bookmarks for this file")) + (unless (and bmkp-current-nav-bookmark (not startoverp) + (bmkp-get-bookmark bmkp-current-nav-bookmark 'NOERROR) + (bmkp-this-file-p bmkp-current-nav-bookmark)) ; Exclude desktops etc. + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist))) + (if (bmkp-cycle-1 increment other-window startoverp) + (unless (or (bmkp-sequence-bookmark-p bmkp-current-nav-bookmark) + (bmkp-function-bookmark-p bmkp-current-nav-bookmark)) + (message "Position: %9d, Bookmark: `%s'" + (point) (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark))) + (message "Invalid bookmark: `%s'" (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark)))) + +;;;###autoload (autoload 'bmkp-cycle-this-file-other-window "bookmark+") +(defun bmkp-cycle-this-file-other-window (increment &optional startoverp) + "Same as `bmkp-cycle-this-file' but use other window." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-file increment 'OTHER-WINDOW startoverp)) + +;;;###autoload (autoload 'bmkp-cycle-this-buffer "bookmark+") +(defun bmkp-cycle-this-buffer (increment &optional other-window startoverp) + "Cycle through bookmarks in this buffer by INCREMENT (default: 1). +Positive INCREMENT cycles forward. Negative INCREMENT cycles backward. +Interactively, the prefix arg determines INCREMENT: + Plain `C-u': 1 + otherwise: the numeric prefix arg value + +Plain `C-u' also means start over at first bookmark. + +You can cycle among bookmarks beyond the current buffer using +`bmkp-cycle' and `bmkp-cycle-other-window.' + +You can set your preferred sort order for this-buffer bookmarks by +customizing option `bmkp-this-file/buffer-cycle-sort-comparer'. + +To change the sort order without customizing, you can use \ +`\\[bmkp-this-buffer-bmenu-list]' to +show the `*Bookmark List*' with only this buffer's bookmarks, sort +them there, and use `\\[bmkp-choose-navlist-from-bookmark-list]', choosing \ +`CURRENT *Bookmark List*' as +the navigation list. + +Then you can cycle the bookmarks using `bmkp-cycle' +\(`\\[bmkp-next-bookmark-repeat]' etc.), instead of `bmkp-cycle-this-buffer'. + +In Lisp code: + Non-nil OTHER-WINDOW means jump to the bookmark in another window. + Non-nil STARTOVERP means reset `bmkp-current-nav-bookmark' to the + first bookmark in the navlist." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) nil startovr))) + (bookmark-maybe-load-default-file) + (let ((bmkp-sort-comparer bmkp-this-file/buffer-cycle-sort-comparer)) + (setq bmkp-nav-alist (bmkp-sort-omit (bmkp-this-buffer-alist-only)))) + (unless bmkp-nav-alist (error "No bookmarks in this buffer")) + (unless (and bmkp-current-nav-bookmark (not startoverp) + (bmkp-get-bookmark bmkp-current-nav-bookmark 'NOERROR) + (bmkp-this-buffer-p bmkp-current-nav-bookmark)) ; Exclude desktops etc. + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist))) + (if (bmkp-cycle-1 increment other-window startoverp) + (unless (or (bmkp-sequence-bookmark-p bmkp-current-nav-bookmark) + (bmkp-function-bookmark-p bmkp-current-nav-bookmark)) + (message "Position: %9d, Bookmark: `%s'" + (point) (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark))) + (message "Invalid bookmark: `%s'" (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark)))) + +;;;###autoload (autoload 'bmkp-cycle-this-buffer-other-window "bookmark+") +(defun bmkp-cycle-this-buffer-other-window (increment &optional startoverp) + "Same as `bmkp-cycle-this-buffer' but use other window." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-buffer increment 'OTHER-WINDOW startoverp)) + +(defun bmkp-cycle-1 (increment &optional other-window startoverp) + "Helper for `bmkp-cycle*' commands. +Do nothing if `bmkp-current-nav-bookmark' is an invalid bookmark. +Return `bmkp-current-nav-bookmark', or nil if invalid. + +NOTE: If `pop-up-frames' is non-nil, then cycling inhibits automatic +showing of annotations (`bookmark-automatically-show-annotations'). +This is to prevent change of frame focus, so cycling can continue +properly. + +See `bmkp-cycle' for descriptions of the arguments." + (let ((bookmark-alist bmkp-nav-alist) + (bookmark (bmkp-get-bookmark bmkp-current-nav-bookmark 'NOERROR)) + (bmkp-use-region (eq 'cycling-too bmkp-use-region))) + (unless bookmark-alist (error "No bookmarks for cycling")) + (when bookmark ; Skip bookmarks with bad names. + (setq bmkp-current-nav-bookmark + (if startoverp + (car bookmark-alist) + (let ((index (bmkp-list-position bookmark bookmark-alist #'eq))) + (if index + (nth (mod (+ increment index) (length bookmark-alist)) bookmark-alist) + (message "bmkp-cycle-1: Bookmark `%s' is not in navlist" + (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark)) + (car bookmark-alist))))) + (let ((bookmark-automatically-show-annotations ; Prevent possible frame focus change. + (and bookmark-automatically-show-annotations (not pop-up-frames)))) + (if other-window + (bookmark-jump-other-window (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark)) + (save-selected-window (bmkp-bookmark-name-from-record (bookmark-jump bmkp-current-nav-bookmark)))))) + (and bookmark bmkp-current-nav-bookmark))) ; Return nil if not a valid bookmark. + +;; Same as `icicle-list-position' in `icicles-fn.el'. +;; Simple version of `cl-position' for all Emacs versions. +(defun bmkp-list-position (item items &optional test) + "Find the first occurrence of ITEM in list ITEMS. +Return the index of the matching item, or nil if not found. +Items are compared using binary predicate TEST, or `equal' if TEST is +nil." + (unless test (setq test 'equal)) + (let ((pos 0)) + (catch 'bmkp-list-position + (dolist (itm items) + (when (funcall test item itm) (throw 'bmkp-list-position pos)) + (setq pos (1+ pos))) + nil))) + +;;;###autoload (autoload 'bmkp-next-bookmark "bookmark+") +(defun bmkp-next-bookmark (n &optional startoverp) ; You can bind this to a repeatable key + "Jump to the Nth next bookmark in the bookmark navigation list. +N defaults to 1, meaning the next bookmark. +Plain `C-u' means start over at first bookmark. +See also `bmkp-cycle'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle n nil startoverp)) + +;;;###autoload (autoload 'bmkp-previous-bookmark "bookmark+") +(defun bmkp-previous-bookmark (n &optional startoverp) ; You can bind this to a repeatable key + "Jump to the Nth previous bookmark in the bookmark navigation list. +See `bmkp-next-bookmark'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle (- n) nil startoverp)) + +;;;###autoload (autoload 'bmkp-next-bookmark-other-window "bookmark+") +(defun bmkp-next-bookmark-other-window (n &optional startoverp) ; You can bind this to a repeatable key + "Jump to Nth next bookmark in bookmark navlist in another window. +N defaults to 1, meaning the next bookmark. +Plain `C-u' means start over at first bookmark. +See also `bmkp-cycle'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle n 'OTHER-WINDOW startoverp)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-other-window "bookmark+") +(defun bmkp-previous-bookmark-other-window (n &optional startoverp) ; You can bind this to a repeatable key + "Jump to Nth previous bookmark in bookmark navlist in another window. +See `bmkp-next-bookmark'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle (- n) 'OTHER-WINDOW startoverp)) + +;;;###autoload (autoload 'bmkp-next-bookmark-repeat "bookmark+") +(defun bmkp-next-bookmark-repeat (arg) ; `C-x x right', `C-x x f', `C-x x C-f' + "Jump to the Nth-next bookmark in the bookmark navigation list. +This is a repeatable version of `bmkp-next-bookmark'. +N defaults to 1, meaning the next bookmark. +Plain `C-u' means start over at the first bookmark (and no repeat)." + (interactive "P") + (bmkp-repeat-command 'bmkp-next-bookmark)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-repeat "bookmark+") +(defun bmkp-previous-bookmark-repeat (arg) ; `C-x x left', `C-x x b', `C-x x C-b' + "Jump to the Nth-previous bookmark in the bookmark navigation list. +See `bmkp-next-bookmark-repeat'." + (interactive "P") + (bmkp-repeat-command 'bmkp-previous-bookmark)) + +;;;###autoload (autoload 'bmkp-next-bookmark-other-window-repeat "bookmark+") +(defun bmkp-next-bookmark-other-window-repeat (arg) ; `C-x x right', `C-x x f', `C-x x C-f' + "Jump to Nth-next bookmark in bookmark navlist in another window. +This is a repeatable version of `bmkp-next-bookmark'. +N defaults to 1, meaning the next bookmark. +Plain `C-u' means start over at the first bookmark (and no repeat)." + (interactive "P") + (bmkp-repeat-command 'bmkp-next-bookmark-other-window)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-other-window-repeat "bookmark+") +(defun bmkp-previous-bookmark-other-window-repeat (arg) ; `C-x x left', `C-x x b', `C-x x C-b' + "Jump to Nth-previous bookmark in bookmark navlist in another window. +See `bmkp-next-bookmark-repeat'." + (interactive "P") + (bmkp-repeat-command 'bmkp-previous-bookmark-other-window)) + +;;;###autoload (autoload 'bmkp-next-bookmark-this-file/buffer "bookmark+") +(defun bmkp-next-bookmark-this-file/buffer (n &optional startoverp) ; Bind to repeatable key, e.g. `S-f2' + "Jump to the Nth-next bookmark for the current file/buffer. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one. +See also `bmkp-cycle-this-file/buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-file/buffer n nil startoverp)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-this-file/buffer "bookmark+") +(defun bmkp-previous-bookmark-this-file/buffer (n &optional startoverp) ; Bind to repeatable key, e.g. `f2' + "Jump to the Nth-previous bookmark for the current file/buffer. +See `bmkp-next-bookmark-this-file/buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-file/buffer (- n) nil startoverp)) + +;;;###autoload (autoload 'bmkp-next-bookmark-this-file/buffer-repeat "bookmark+") +(defun bmkp-next-bookmark-this-file/buffer-repeat (arg) + ; `C-x x down', `C-x x n', `C-x x C-n', `C-x x mouse-wheel-up' + "Jump to the Nth next bookmark for the current file/buffer. +This is a repeatable version of `bmkp-next-bookmark-this-file/buffer'. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one (and no repeat)." + (interactive "P") + (bmkp-repeat-command 'bmkp-next-bookmark-this-file/buffer)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-this-file/buffer-repeat "bookmark+") +(defun bmkp-previous-bookmark-this-file/buffer-repeat (arg) + ; `C-x x up', `C-x x p', `C-x x C-p', `C-x x mouse-wheel-down' + "Jump to the Nth previous bookmark for the current file/buffer. +See `bmkp-next-bookmark-this-file/buffer-repeat'." + (interactive "P") + (bmkp-repeat-command 'bmkp-previous-bookmark-this-file/buffer)) + +;;;###autoload (autoload 'bmkp-next-bookmark-this-file "bookmark+") +(defun bmkp-next-bookmark-this-file (n &optional startoverp) ; Bind to repeatable key, e.g. `S-f2' + "Jump to the Nth-next bookmark for the current file. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one. +See also `bmkp-cycle-this-file'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-file n nil startoverp)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-this-file "bookmark+") +(defun bmkp-previous-bookmark-this-file (n &optional startoverp) ; Bind to repeatable key, e.g. `f2' + "Jump to the Nth-previous bookmark for the current file. +See `bmkp-next-bookmark-this-file'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-file (- n) nil startoverp)) + +;;;###autoload (autoload 'bmkp-next-bookmark-this-file-repeat "bookmark+") +(defun bmkp-next-bookmark-this-file-repeat (arg) + "Jump to the Nth next bookmark for the current file. +This is a repeatable version of `bmkp-next-bookmark-this-file'. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one (and no repeat)." + (interactive "P") + (bmkp-repeat-command 'bmkp-next-bookmark-this-file)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-this-file-repeat "bookmark+") +(defun bmkp-previous-bookmark-this-file-repeat (arg) + "Jump to the Nth previous bookmark for the current file. +See `bmkp-next-bookmark-this-file-repeat'." + (interactive "P") + (bmkp-repeat-command 'bmkp-previous-bookmark-this-file)) + + +;;;###autoload (autoload 'bmkp-next-bookmark-this-buffer "bookmark+") +(defun bmkp-next-bookmark-this-buffer (n &optional startoverp) ; Bind to repeatable key, e.g. `S-f2' + "Jump to the Nth-next bookmark in the current buffer. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one. +See also `bmkp-cycle-this-buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-buffer n nil startoverp)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-this-buffer "bookmark+") +(defun bmkp-previous-bookmark-this-buffer (n &optional startoverp) ; Bind to repeatable key, e.g. `f2' + "Jump to the Nth-previous bookmark in the current buffer. +See `bmkp-next-bookmark-this-buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-this-buffer (- n) nil startoverp)) + +;;;###autoload (autoload 'bmkp-next-bookmark-this-buffer-repeat "bookmark+") +(defun bmkp-next-bookmark-this-buffer-repeat (arg) + "Jump to the Nth next bookmark in the current buffer. +This is a repeatable version of `bmkp-next-bookmark-this-buffer'. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one (and no repeat)." + (interactive "P") + (bmkp-repeat-command 'bmkp-next-bookmark-this-buffer)) + +;;;###autoload (autoload 'bmkp-previous-bookmark-this-buffer-repeat "bookmark+") +(defun bmkp-previous-bookmark-this-buffer-repeat (arg) + "Jump to the Nth previous bookmark in the current buffer. +See `bmkp-next-bookmark-this-buffer-repeat'." + (interactive "P") + (bmkp-repeat-command 'bmkp-previous-bookmark-this-buffer)) + +;;;###autoload (autoload 'bmkp-next-bookmark-w32 "bookmark+") +(defun bmkp-next-bookmark-w32 (n &optional startoverp) ; You can bind this to a repeatable key + "Windows `Open' the Nth next bookmark in the bookmark navigation list. +MS Windows only. Invokes the program associated with the file type. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one. +See also `bmkp-cycle'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (let ((bmkp-use-w32-browser-p t)) (bmkp-cycle n nil startoverp))) + +;;;###autoload (autoload 'bmkp-previous-bookmark-w32 "bookmark+") +(defun bmkp-previous-bookmark-w32 (n &optional startoverp) ; You can bind this to a repeatable key + "Windows `Open' the Nth previous bookmark in the bookmark navlist. +See `bmkp-next-bookmark-w32'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (let ((bmkp-use-w32-browser-p t)) (bmkp-cycle (- n) nil startoverp))) + +;;;###autoload (autoload 'bmkp-next-bookmark-w32-repeat "bookmark+") +(defun bmkp-next-bookmark-w32-repeat (arg) ; `C-x x next' + "Windows `Open' the Nth next bookmark in the bookmark navigation list. +This is a repeatable version of `bmkp-next-bookmark'. +N defaults to 1, meaning the next bookmark. +Plain `C-u' means start over at the first one (and no repeat)." + (interactive "P") + (let ((bmkp-use-w32-browser-p t)) (bmkp-repeat-command 'bmkp-next-bookmark))) + +;;;###autoload (autoload 'bmkp-previous-bookmark-w32-repeat "bookmark+") +(defun bmkp-previous-bookmark-w32-repeat (arg) ; `C-x x prior' + "Windows `Open' the Nth previous bookmark in the bookmark navlist. +See `bmkp-next-bookmark-w32-repeat'." + (interactive "P") + (let ((bmkp-use-w32-browser-p t)) (bmkp-repeat-command 'bmkp-previous-bookmark))) + +;; In spite of their names, `bmkp-cycle-specific-(buffers|files)*' just cycle bookmarks in the +;; current buffer or file. There is no way to choose multiple buffers or files. +;; +;; `bmkp-cycle-autonamed', `bmkp-cycle-autonamed-other-window', +;; `bmkp-cycle-bookmark-list', `bmkp-cycle-bookmark-list-other-window', +;; `bmkp-cycle-desktop', +;; `bmkp-cycle-dired', `bmkp-cycle-dired-other-window', +;; `bmkp-cycle-eww', `bmkp-cycle-eww-other-window', +;; `bmkp-cycle-file', `bmkp-cycle-file-other-window', +;; `bmkp-cycle-gnus', `bmkp-cycle-gnus-other-window', +;; `bmkp-cycle-info', `bmkp-cycle-info-other-window', +;; `bmkp-cycle-lighted', `bmkp-cycle-lighted-other-window', +;; `bmkp-cycle-local-file', `bmkp-cycle-local-file-other-window', +;; `bmkp-cycle-man', `bmkp-cycle-man-other-window', +;; `bmkp-cycle-non-file', `bmkp-cycle-non-file-other-window', +;; `bmkp-cycle-remote-file', `bmkp-cycle-remote-file-other-window', +;; `bmkp-cycle-specific-buffers', `bmkp-cycle-specific-buffers-other-window', +;; `bmkp-cycle-specific-files', `bmkp-cycle-specific-files-other-window', +;; `bmkp-cycle-variable-list', +;; `bmkp-cycle-url', `bmkp-cycle-url-other-window', +;; +(bmkp-define-cycle-command "autonamed") +(bmkp-define-cycle-command "autonamed" 'OTHER-WINDOW) +(bmkp-define-cycle-command "bookmark-list") ; No other-window version needed +(bmkp-define-cycle-command "desktop") ; No other-window version needed +(bmkp-define-cycle-command "dired") +(bmkp-define-cycle-command "dired" 'OTHER-WINDOW) +(bmkp-define-cycle-command "eww") +(bmkp-define-cycle-command "eww" 'OTHER-WINDOW) +(bmkp-define-cycle-command "file") +(bmkp-define-cycle-command "file" 'OTHER-WINDOW) +(bmkp-define-cycle-command "gnus") +(bmkp-define-cycle-command "gnus" 'OTHER-WINDOW) +(bmkp-define-cycle-command "info") +(bmkp-define-cycle-command "info" 'OTHER-WINDOW) +(when (featurep 'bookmark+-lit) + (bmkp-define-cycle-command "lighted") + (bmkp-define-cycle-command "lighted" 'OTHER-WINDOW)) +(bmkp-define-cycle-command "local-file") +(bmkp-define-cycle-command "local-file" 'OTHER-WINDOW) +(bmkp-define-cycle-command "man") +(bmkp-define-cycle-command "man" 'OTHER-WINDOW) +(bmkp-define-cycle-command "non-file") +(bmkp-define-cycle-command "non-file" 'OTHER-WINDOW) +(bmkp-define-cycle-command "remote-file") +(bmkp-define-cycle-command "remote-file" 'OTHER-WINDOW) +(bmkp-define-cycle-command "specific-buffers") +(bmkp-define-cycle-command "specific-buffers" 'OTHER-WINDOW) +(bmkp-define-cycle-command "specific-files") +(bmkp-define-cycle-command "specific-files" 'OTHER-WINDOW) +(bmkp-define-cycle-command "variable-list") ; No other-window version needed +(bmkp-define-cycle-command "url") +(bmkp-define-cycle-command "url" 'OTHER-WINDOW) + +;; `bmkp-next-autonamed-bookmark', `bmkp-next-autonamed-bookmark-other-window', +;; `bmkp-next-autonamed-bookmark-repeat', `bmkp-next-autonamed-bookmark-other-window-repeat', +;; `bmkp-next-bookmark-list-bookmark', +;; `bmkp-next-bookmark-list-bookmark-repeat', +;; `bmkp-next-bookmark-list-bookmark-other-window', +;; `bmkp-next-bookmark-list-bookmark-other-window-repeat', +;; `bmkp-next-desktop-bookmark', +;; `bmkp-next-desktop-bookmark-repeat', +;; `bmkp-next-desktop-bookmark-other-window', +;; `bmkp-next-desktop-bookmark-other-window-repeat', +;; `bmkp-next-dired-bookmark', +;; `bmkp-next-dired-bookmark-repeat', +;; `bmkp-next-dired-bookmark-other-window', +;; `bmkp-next-dired-bookmark-other-window-repeat', +;; `bmkp-next-eww-bookmark', +;; `bmkp-next-eww-bookmark-repeat', +;; `bmkp-next-eww-bookmark-other-window', +;; `bmkp-next-eww-bookmark-other-window-repeat', +;; `bmkp-next-file-bookmark', +;; `bmkp-next-file-bookmark-repeat', +;; `bmkp-next-file-bookmark-other-window', +;; `bmkp-next-file-bookmark-other-window-repeat', +;; `bmkp-next-gnus-bookmark', +;; `bmkp-next-gnus-bookmark-repeat', +;; `bmkp-next-gnus-bookmark-other-window', +;; `bmkp-next-gnus-bookmark-other-window-repeat', +;; `bmkp-next-info-bookmark', +;; `bmkp-next-info-bookmark-repeat', +;; `bmkp-next-info-bookmark-other-window', +;; `bmkp-next-info-bookmark-other-window-repeat', +;; `bmkp-next-lighted-bookmark', +;; `bmkp-next-lighted-bookmark-repeat', +;; `bmkp-next-lighted-bookmark-other-window', +;; `bmkp-next-lighted-bookmark-other-window-repeat', +;; `bmkp-next-local-file-bookmark', +;; `bmkp-next-local-file-bookmark-repeat', +;; `bmkp-next-local-file-bookmark-other-window', +;; `bmkp-next-local-file-bookmark-other-window-repeat', +;; `bmkp-next-man-bookmark', +;; `bmkp-next-man-bookmark-repeat', +;; `bmkp-next-man-bookmark-other-window', +;; `bmkp-next-man-bookmark-other-window-repeat', +;; `bmkp-next-non-file-bookmark', +;; `bmkp-next-non-file-bookmark-repeat', +;; `bmkp-next-non-file-bookmark-other-window', +;; `bmkp-next-non-file-bookmark-other-window-repeat', +;; `bmkp-next-remote-file-bookmark', +;; `bmkp-next-remote-file-bookmark-repeat', +;; `bmkp-next-remote-file-bookmark-other-window', +;; `bmkp-next-remote-file-bookmark-other-window-repeat', +;; `bmkp-next-specific-buffers-bookmark', +;; `bmkp-next-specific-buffers-bookmark-repeat', +;; `bmkp-next-specific-buffers-bookmark-other-window', +;; `bmkp-next-specific-buffers-bookmark-other-window-repeat', +;; `bmkp-next-specific-files-bookmark', +;; `bmkp-next-specific-files-bookmark-repeat', +;; `bmkp-next-specific-files-bookmark-other-window', +;; `bmkp-next-specific-files-bookmark-other-window-repeat', +;; `bmkp-next-variable-list-bookmark', +;; `bmkp-next-variable-list-bookmark-repeat', +;; `bmkp-next-variable-list-bookmark-other-window', +;; `bmkp-next-variable-list-bookmark-other-window-repeat', +;; `bmkp-next-url-bookmark', +;; `bmkp-next-url-bookmark-repeat'. +;; `bmkp-next-url-bookmark-other-window', +;; `bmkp-next-url-bookmark-other-window-repeat'. +;; +;; `bmkp-previous-autonamed-bookmark', +;; `bmkp-previous-autonamed-bookmark-repeat', +;; `bmkp-previous-autonamed-bookmark-other-window', +;; `bmkp-previous-autonamed-bookmark-other-window-repeat', +;; `bmkp-previous-bookmark-list-bookmark', +;; `bmkp-previous-bookmark-list-bookmark-repeat', +;; `bmkp-previous-bookmark-list-bookmark-other-window', +;; `bmkp-previous-bookmark-list-bookmark-other-window-repeat', +;; `bmkp-previous-desktop-bookmark', +;; `bmkp-previous-desktop-bookmark-repeat', +;; `bmkp-previous-desktop-bookmark-other-window', +;; `bmkp-previous-desktop-bookmark--other-windowrepeat', +;; `bmkp-previous-dired-bookmark', +;; `bmkp-previous-dired-bookmark-repeat', +;; `bmkp-previous-dired-bookmark-other-window', +;; `bmkp-previous-dired-bookmark-other-window-repeat', +;; `bmkp-previous-eww-bookmark', +;; `bmkp-previous-eww-bookmark-repeat', +;; `bmkp-previous-eww-bookmark-other-window', +;; `bmkp-previous-eww-bookmark-other-window-repeat', +;; `bmkp-previous-file-bookmark', +;; `bmkp-previous-file-bookmark-repeat', +;; `bmkp-previous-file-bookmark-other-window', +;; `bmkp-previous-file-bookmark-other-window-repeat', +;; `bmkp-previous-gnus-bookmark', +;; `bmkp-previous-gnus-bookmark-repeat', +;; `bmkp-previous-gnus-bookmark-other-window', +;; `bmkp-previous-gnus-bookmark-other-window-repeat', +;; `bmkp-previous-info-bookmark', +;; `bmkp-previous-info-bookmark-repeat', +;; `bmkp-previous-info-bookmark-other-window', +;; `bmkp-previous-info-bookmark-other-window-repeat', +;; `bmkp-previous-lighted-bookmark', +;; `bmkp-previous-lighted-bookmark-repeat', +;; `bmkp-previous-lighted-bookmark-other-window', +;; `bmkp-previous-lighted-bookmark-other-window-repeat', +;; `bmkp-previous-local-file-bookmark', +;; `bmkp-previous-local-file-bookmark-repeat', +;; `bmkp-previous-local-file-bookmark-other-window', +;; `bmkp-previous-local-file-bookmark-other-window-repeat', +;; `bmkp-previous-man-bookmark', +;; `bmkp-previous-man-bookmark-repeat', +;; `bmkp-previous-man-bookmark-other-window', +;; `bmkp-previous-man-bookmark-other-window-repeat', +;; `bmkp-previous-non-file-bookmark', +;; `bmkp-previous-non-file-bookmark-repeat', +;; `bmkp-previous-non-file-bookmark-other-window', +;; `bmkp-previous-non-file-bookmark-other-window-repeat', +;; `bmkp-previous-remote-file-bookmark', +;; `bmkp-previous-remote-file-bookmark-repeat', +;; `bmkp-previous-remote-file-bookmark-other-window', +;; `bmkp-previous-remote-file-bookmark--other-windowrepeat', +;; `bmkp-previous-specific-buffers-bookmark', +;; `bmkp-previous-specific-buffers-bookmark-repeat', +;; `bmkp-previous-specific-buffers-bookmark-other-window', +;; `bmkp-previous-specific-buffers-bookmark-other-window-repeat', +;; `bmkp-previous-specific-files-bookmark', +;; `bmkp-previous-specific-files-bookmark-repeat', +;; `bmkp-previous-specific-files-bookmark-other-window', +;; `bmkp-previous-specific-files-bookmark-other-window-repeat', +;; `bmkp-previous-variable-list-bookmark', +;; `bmkp-previous-variable-list-bookmark-repeat', +;; `bmkp-previous-variable-list-bookmark-other-window', +;; `bmkp-previous-variable-list-bookmark-other-window-repeat', +;; `bmkp-previous-url-bookmark', +;; `bmkp-previous-url-bookmark-repeat'. +;; `bmkp-previous-url-bookmark-other-window', +;; `bmkp-previous-url-bookmark-other-window-repeat'. +;; +(bmkp-define-next+prev-cycle-commands "autonamed") +(bmkp-define-next+prev-cycle-commands "autonamed" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "bookmark-list") +(bmkp-define-next+prev-cycle-commands "desktop") +(bmkp-define-next+prev-cycle-commands "dired") +(bmkp-define-next+prev-cycle-commands "dired" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "eww") +(bmkp-define-next+prev-cycle-commands "eww" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "file") +(bmkp-define-next+prev-cycle-commands "file" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "gnus") +(bmkp-define-next+prev-cycle-commands "gnus" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "info") +(bmkp-define-next+prev-cycle-commands "info" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "lighted") +(bmkp-define-next+prev-cycle-commands "lighted" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "local-file") +(bmkp-define-next+prev-cycle-commands "local-file" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "man") +(bmkp-define-next+prev-cycle-commands "man" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "non-file") +(bmkp-define-next+prev-cycle-commands "non-file" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "remote-file") +(bmkp-define-next+prev-cycle-commands "remote-file" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "specific-buffers") +(bmkp-define-next+prev-cycle-commands "specific-buffers" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "specific-files") +(bmkp-define-next+prev-cycle-commands "specific-files" 'OTHER-WINDOW) +(bmkp-define-next+prev-cycle-commands "variable-list") +(bmkp-define-next+prev-cycle-commands "url") +(bmkp-define-next+prev-cycle-commands "url" 'OTHER-WINDOW) + +;;;###autoload (autoload 'bmkp-toggle-autonamed-bookmark-set/delete "bookmark+") +(defun bmkp-toggle-autonamed-bookmark-set/delete (&optional position allp) + ; Bound globally to `C-x x RET', `C-x x c RET' + "If there is an autonamed bookmark at point, delete it, else create one. +The bookmark created has no region. Its name is formatted according +to option `bmkp-autoname-bookmark-function'. + +With a prefix arg, delete *ALL* autonamed bookmarks for this buffer. + +Non-interactively, act at POSITION, not point. If nil, act at point." + (interactive "d\nP") + (unless position (setq position (point))) + (if allp + (bmkp-delete-all-autonamed-for-this-buffer) + (let ((bmk-name (funcall bmkp-autoname-bookmark-function position))) + (if (not (bmkp-get-bookmark-in-alist bmk-name 'NOERROR)) + (let ((mark-active nil)) ; Do not set a region bookmark. + (bookmark-set bmk-name) + (message "Set bookmark `%s'" bmk-name)) + (bookmark-delete bmk-name) + (message "Deleted bookmark `%s'" bmk-name))))) + +;;;###autoload (autoload 'bmkp-set-autonamed-bookmark "bookmark+") +(defun bmkp-set-autonamed-bookmark (&optional position msg-p) + "Set an autonamed bookmark at point. +The bookmark created has no region. Its name is formatted according +to option `bmkp-autoname-bookmark-function'. +Non-interactively: + - Act at POSITION, not point. If nil, act at point. + - Non-nil optional arg MSG-P means display a status message." + (interactive (list (point) 'MSG)) + (unless position (setq position (point))) + (let ((bmk-name (funcall bmkp-autoname-bookmark-function position)) + (mark-active nil)) ; Do not set a region bookmark. + (bookmark-set bmk-name) + (when msg-p (message "Set bookmark `%s'" bmk-name)))) + +;;;###autoload (autoload 'bmkp-set-autonamed-bookmark-at-line "bookmark+") +(defun bmkp-set-autonamed-bookmark-at-line (&optional number) + "Set an autonamed bookmark at the beginning of the current line. +With a prefix arg, set it at the line whose number is the numeric +prefix value." + (interactive (list (and current-prefix-arg (prefix-numeric-value current-prefix-arg)))) + (if (not number) + (bmkp-set-autonamed-bookmark (line-beginning-position)) + (save-excursion + (goto-char (point-min)) + (let ((inhibit-field-text-motion t)) + (bmkp-set-autonamed-bookmark (line-beginning-position number)))))) + +(when (> emacs-major-version 21) + (defun bmkp-occur-create-autonamed-bookmarks (&optional msg-p) ; Bound to `C-c C-M-B' (aka `C-c C-M-S-b') + "Create an autonamed bookmark for each `occur' hit. +You can use this only in `Occur' mode (commands such as `occur' and +`multi-occur'). +Non-interactively, non-nil MSG-P means display a status message." + (interactive "p") + (unless (eq major-mode 'occur-mode) (error "You must be in `occur-mode'")) + (let ((count 0)) + (save-excursion + (goto-char (point-min)) + (while (condition-case nil (progn (occur-next) t) (error nil)) + (let* ((pos (get-text-property (point) 'occur-target)) + (buf (and pos (marker-buffer pos)))) + (when buf + (with-current-buffer buf + (goto-char pos) + (bmkp-set-autonamed-bookmark (point))) + (setq count (1+ count)))))) + (when msg-p (message "Created %d autonamed bookmarks" count))))) + +;;;###autoload (autoload 'bmkp-set-autonamed-regexp-buffer "bookmark+") +(defun bmkp-set-autonamed-regexp-buffer (regexp &optional msg-p) + "Set autonamed bookmarks at matches for REGEXP in the buffer. +Non-interactively, non-nil MSG-P means display a status message." + (interactive (list (bmkp-read-regexp) 'MSG)) + (bmkp-set-autonamed-regexp-region regexp (point-min) (point-max) msg-p)) + +;;;###autoload (autoload 'bmkp-set-autonamed-regexp-region "bookmark+") +(defun bmkp-set-autonamed-regexp-region (regexp beg end &optional msg-p) + "Set autonamed bookmarks at matches for REGEXP in the region. +Non-interactively, non-nil MSG-P means display a status message." + (interactive (list (bmkp-read-regexp) (region-beginning) (region-end) 'MSG)) + (let ((count 0)) + (save-excursion + (goto-char beg) + (while (re-search-forward regexp end t) + (bmkp-set-autonamed-bookmark (point)) + (setq count (1+ count)) + (forward-line 1))) + (when msg-p (message "Set %d autonamed bookmarks" count)))) + +(defun bmkp-autoname-bookmark-function-default (position) + "Return a bookmark name using POSITION and the current buffer name. +The name is composed as follows: + POSITION followed by a space and then the buffer name. + The position value is prefixed with zeros to comprise 9 characters. + For example, for POSITION value 31416 and current buffer `my-buffer', + the name returned would be `000031416 my-buffer'" + (format "%09d %s" (abs position) (buffer-name))) + +;;;###autoload (autoload 'bmkp-delete-all-autonamed-for-this-buffer "bookmark+") +(defun bmkp-delete-all-autonamed-for-this-buffer (&optional msg-p) + "Delete all autonamed bookmarks for the current buffer. +Interactively, or with non-nil arg MSG-P, require confirmation. +To be deleted, a bookmark name must be an autonamed bookmark whose +buffer part names the current buffer." + (interactive "p") + (let ((bmks-to-delete (mapcar #'bmkp-bookmark-name-from-record + (bmkp-autonamed-this-buffer-alist-only)))) + (if (null bmks-to-delete) + (when msg-p (message "No autonamed bookmarks for buffer `%s'" (buffer-name))) + (when (or (not msg-p) + (y-or-n-p (format "Delete ALL autonamed bookmarks for buffer `%s'? " (buffer-name)))) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk bmks-to-delete) (bookmark-delete bmk 'BATCHP))) ; No refresh yet. + (bmkp-refresh/rebuild-menu-list nil (not msg-p)) ; Now refresh, after iterate. + (when msg-p (message "Deleted all bookmarks for buffer `%s'" (buffer-name))))))) + +;; You can use this in `kill-buffer-hook'. +(defun bmkp-delete-autonamed-this-buffer-no-confirm (&optional no-refresh-p) + "Delete all autonamed bookmarks for this buffer, without confirmation. +Non-nil optional arg NO-REFRESH-P means do not refresh/rebuild the +bookmark-list." + (when (and bookmarks-already-loaded bookmark-alist) + (let ((bmks-to-delete (mapcar #'bmkp-bookmark-name-from-record + (bmkp-autonamed-this-buffer-alist-only))) + (bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk bmks-to-delete) (bookmark-delete bmk 'BATCHP))) ; No refresh yet. + (unless no-refresh-p + (bmkp-refresh/rebuild-menu-list nil 'BATCHP)))) ; Now refresh, after iterate. + + +;; You can use this in `kill-emacs-hook'. +(defun bmkp-delete-autonamed-no-confirm () + "Delete all autonamed bookmarks for all buffers, without confirmation." + (when (and bookmarks-already-loaded bookmark-alist) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (buf (buffer-list)) + (with-current-buffer buf + (bmkp-delete-autonamed-this-buffer-no-confirm 'NO-REFRESH-P)))) ; No refresh yet. + (bmkp-refresh/rebuild-menu-list nil 'BATCHP))) ; Now refresh, after iterate. + +(cond ((fboundp 'define-minor-mode) + ;; Emacs 21 and later. Eval this so that even if the library is byte-compiled with Emacs 20, + ;; loading it into Emacs 21+ will define variable `bmkp-automatic-bookmark-mode'. + (eval '(define-minor-mode bmkp-automatic-bookmark-mode + "Toggle automatic setting of a bookmark when Emacs is idle. +Non-interactively, turn automatic bookmarking on for the current +buffer if and only if ARG is positive. + +To enable or disable automatic bookmarking in all buffers, use +`bmkp-global-automatic-bookmark-mode'. + +When the mode is enabled in the current buffer, a bookmark is +automatically set every `bmkp-automatic-bookmark-mode-delay' seconds, +using the setting function that is the value of option +`bmkp-automatic-bookmark-set-function'. Note that a buffer must be +current (selected) for an automatic bookmark to be created there - it +is not enough that the mode be enabled in the buffer. + +Turning the mode on and off runs hooks +`bmkp-automatic-bookmark-mode-on-hook' and +`bmkp-automatic-bookmark-mode-off-hook', respectively. + +If you want the automatic bookmarks to be temporary (not saved to your +bookmark file), then customize option +`bmkp-autotemp-bookmark-predicates' so that it includes the kind of +bookmarks that are set by `bmkp-automatic-bookmark-set-function'. +For example, if automatic bookmarking sets autonamed bookmarks, then +`bmkp-autotemp-bookmark-predicates' should include +`bmkp-autonamed-bookmark-p' or +`bmkp-autonamed-this-buffer-bookmark-p'. + +If you want the automatically created bookmarks to be highlighted, +then customize option `bmkp-auto-light-when-set' to highlight +bookmarks of the appropriate kind. For example, to highlight +autonamed bookmarks set it to `autonamed-bookmark'. + +NOTE: If you use Emacs 21 then there is no global version of the mode +- that is, there is no command `bmkp-global-automatic-bookmark-mode'." + :init-value nil :group 'bookmark-plus :require 'bookmark+ + :lighter bmkp-automatic-bookmark-mode-lighter + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +Bookmark bug: \ +&body=Describe bug here, starting with `emacs -Q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Download" "https://www.emacswiki.org/emacs/download/bookmark%2b.el") + :link '(url-link :tag "Description" "https://www.emacswiki.org/emacs/BookmarkPlus") + :link '(emacs-commentary-link :tag "Commentary" "bookmark+") + (when bmkp-automatic-bookmark-mode-timer + (cancel-timer bmkp-automatic-bookmark-mode-timer) + (setq bmkp-automatic-bookmark-mode-timer nil)) + (when bmkp-automatic-bookmark-mode + (setq bmkp-automatic-bookmark-mode-timer + (run-with-idle-timer bmkp-automatic-bookmark-mode-delay 'REPEAT + (lambda () + (when bmkp-automatic-bookmark-mode + (bmkp-set-automatic-bookmark)))))) + (when (interactive-p) + (message "Automatic bookmarking is now %s in buffer `%s'" + (if bmkp-automatic-bookmark-mode "ON" "OFF") (buffer-name))))) + + (eval '(defun bmkp-turn-on-automatic-bookmark-mode () + "Turn on `bmkp-automatic-bookmark-mode'." + (bmkp-automatic-bookmark-mode 1))) + + (when (fboundp 'define-globalized-minor-mode) ; Emacs 22+, not 21. + (eval '(define-globalized-minor-mode bmkp-global-automatic-bookmark-mode + bmkp-automatic-bookmark-mode + bmkp-turn-on-automatic-bookmark-mode + :group 'bookmark-plus :require 'bookmark+)))) + (t ; Emacs 20. + (defun bmkp-automatic-bookmark-mode (&optional arg) + "Toggle automatic setting of a bookmark when Emacs is idle. +Non-interactively, turn automatic bookmarking on if and only if ARG is +positive. + +When the mode is enabled, a bookmark is automatically set every +`bmkp-automatic-bookmark-mode-delay' seconds, using the setting +function that is the value of option +`bmkp-automatic-bookmark-set-function'. Note that a buffer must be +current (selected) for an automatic bookmark to be created there - it +is not enough that the mode be enabled in the buffer. + +If you want these bookmarks to be temporary (not saved to your +bookmark file), then customize option +`bmkp-autotemp-bookmark-predicates' so that it includes the kind of +bookmarks that are set by `bmkp-automatic-bookmark-set-function'. For +example, if automatic bookmarking sets autonamed bookmarks, then +`bmkp-autotemp-bookmark-predicates' should include +`bmkp-autonamed-bookmark-p'. + +If you want the automatically created bookmarks to be highlighted, +then customize option `bmkp-auto-light-when-set' to highlight +bookmarks of the appropriate kind. For example, to highlight +autonamed bookmarks set it to `autonamed-bookmark'. + +NOTE: This is the Emacs 20 version of `bmkp-automatic-bookmark-mode', +which is global only, that is, all buffers are affected. If you +instead want it to be local only, then do both of the following in +your init file: + (make-variable-buffer-local 'bmkp-automatic-bookmark-mode) + (make-variable-buffer-local 'bmkp-automatic-bookmark-mode-timer)" + (interactive (list (or current-prefix-arg 'toggle))) + (setq bmkp-automatic-bookmark-mode (if (eq arg 'toggle) + (not bmkp-automatic-bookmark-mode) + (> (prefix-numeric-value arg) 0))) + (when bmkp-automatic-bookmark-mode-timer + (cancel-timer bmkp-automatic-bookmark-mode-timer) + (setq bmkp-automatic-bookmark-mode-timer nil)) + (when bmkp-automatic-bookmark-mode + (setq bmkp-automatic-bookmark-mode-timer + (run-with-idle-timer bmkp-automatic-bookmark-mode-delay 'REPEAT + (lambda () ; This allows use as a local mode. + (when bmkp-automatic-bookmark-mode (bmkp-set-automatic-bookmark)))))) + (when (interactive-p) + (message "Automatic bookmarking is now %s%s" + (if bmkp-automatic-bookmark-mode "ON" "OFF") + (if (local-variable-if-set-p 'bmkp-automatic-bookmark-mode) + (format " in buffer `%s'" (current-buffer)) + "")))) + + + (add-to-list 'minor-mode-alist `(bmkp-automatic-bookmark-mode + ,bmkp-automatic-bookmark-mode-lighter)))) + +(defun bmkp-not-near-other-automatic-bmks (&optional position) + "Is POSITION far enough from automatic bookmarks to create a new one? +Return non-nil if `bmkp-automatic-bookmark-min-distance' is nil or if +POSITION is at least `bmkp-automatic-bookmark-min-distance' chars from +all other automatic bookmarks in the same buffer. Else return nil." + (unless position (setq position (point))) + (or (not bmkp-automatic-bookmark-min-distance) + (catch 'bmkp-not-near-other-automatic-bmks + (let (bmk-pos) + (dolist (bmk bmkp-automatic-bookmarks) + (when (and (bmkp-this-buffer-p bmk) + (setq bmk-pos (bookmark-get-position bmk)) + (or (not bmk-pos) (< (abs (- position bmk-pos)) bmkp-automatic-bookmark-min-distance))) + (throw 'bmkp-not-near-other-automatic-bmks nil))) + t)))) + +(defun bmkp-set-automatic-bookmark () + "Invoke `bmkp-automatic-bookmark-set-function'. +Do nothing if bookmark would be too near another automatic bookmark." + (when (bmkp-not-near-other-automatic-bmks) + (let ((bmkp-setting-automatic-bmk-p t)) (funcall bmkp-automatic-bookmark-set-function)))) + +(when (> emacs-major-version 21) ; Emacs 22+ (need also `Info-selection-hook'). + + ;; Eval this so that even if the library is byte-compiled with Emacs 20, + ;; loading it into Emacs 22+ will define variable `bmkp-info-auto-bookmark-mode'. + (eval '(define-minor-mode bmkp-info-auto-bookmark-mode + "Toggle automatically setting a bookmark when you visit an Info node. +The bookmark name is \"(MANUAL) `NODE'\", where: + + MANUAL is the name of the current manual (the base file name). + NODE is the name of the current node. + +If option `bmkp-info-auto-type' is `create-or-update' then such a +bookmark is created for the node if none exists. If the option value +is `update-only' then no new bookmark is created automatically, but an +existing bookmark is updated. (Updating a bookmark increments the +recorded number of visits.) You can toggle the option using +`\\[bmkp-toggle-info-auto-type]'." + :init-value nil :global t :group 'bookmark-plus :require 'bookmark+ + :lighter bmkp-automatic-bookmark-mode-lighter + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +Bookmark bug: \ +&body=Describe bug here, starting with `emacs -Q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Download" "https://www.emacswiki.org/emacs/download/bookmark%2b.el") + :link '(url-link :tag "Description" "https://www.emacswiki.org/emacs/BookmarkPlus") + :link '(emacs-commentary-link :tag "Commentary" "bookmark+") + (if bmkp-info-auto-bookmark-mode + (add-hook 'Info-selection-hook 'bmkp-set-info-bookmark-with-node-name) + (remove-hook 'Info-selection-hook 'bmkp-set-info-bookmark-with-node-name)) + (when (interactive-p) + (message "Automatic Info bookmarking is now %s" (if bmkp-info-auto-bookmark-mode "ON" "OFF"))))) + + (defun bmkp-set-info-bookmark-with-node-name (&optional nomsg) + "Maybe bookmark the current Info node using name \"(MANUAL) `NODE'\". +MANUAL is the name of the current manual (the base file name). +NODE is the name of the current node. + +If option `bmkp-info-auto-type' is `create-or-update' then a bookmark +is created for the node if none exists. If it is `update-only' then +no new bookmark is created automatically, but an existing bookmark is +updated. You can use toggle `bmkp-info-auto-type' using +`\\[bmkp-toggle-info-auto-type]'. + +Non-nil optional arg NOMSG means do not display a message saying that +the node was bookmarked." + (interactive) + (when (and (derived-mode-p 'Info-mode) Info-current-node) + (save-excursion + (goto-char (point-min)) + (let* ((bmk-name (and (stringp Info-current-file) + (format "(%s) %s" (file-name-sans-extension + (file-name-nondirectory Info-current-file)) + Info-current-node))) + (bmk (bmkp-bookmark-record-from-name bmk-name 'NOERROR)) + (visits (and bmk (bookmark-prop-get bmk 'visits)))) + (when bmk-name + (cond ((and (not visits) (eq bmkp-info-auto-type 'create-or-update)) + (bookmark-set bmk-name) + (unless nomsg (message "Created bookmark `%s' for Info node" bmk-name))) + (visits + (bmkp-record-visit bmk-name 'BATCHP) + (bmkp-refresh/rebuild-menu-list bmk-name nil) + (bmkp-maybe-save-bookmarks) + (unless nomsg (message "Updated bookmark `%s' for Info node" bmk-name))))))))) + + (defun bmkp-toggle-info-auto-type (&optional msgp) + "Toggle the value of option `bmkp-info-auto-type'." + (interactive "p") + (setq bmkp-info-auto-type (if (eq bmkp-info-auto-type 'create-or-update) 'update-only 'create-or-update)) + (when msgp (message "`bmkp-info-auto-bookmark-mode' now %s" + (if (eq bmkp-info-auto-type 'create-or-update) + "CREATES, as well as updates, Info bookmarks" + "only UPDATES EXISTING Info bookmarks")))) + + ) + +(if (fboundp 'define-minor-mode) + ;; Emacs 21 and later. Eval this so that even if the library is byte-compiled with Emacs 20, + ;; loading it into Emacs 21+ will define variable `bmkp-temporary-bookmarking-mode'. + (eval '(define-minor-mode bmkp-temporary-bookmarking-mode ; `M-L' in `*Bookmark List*'. + "Toggle temporary bookmarking. +Temporary bookmarking means that any bookmark changes (creation, +modification, deletion) are NOT automatically saved. + +Interactively, you are required to confirm turning on the mode. + +When the mode is turned ON: + a. `bookmark-save-flag' is set to nil. + b. `bmkp-current-bookmark-file' is set to a new, empty bookmark file + in directory `temporary-file-directory' (via `make-temp-file'). + c. That file is not saved automatically. + d. In the `*Bookmark List*' display, the major-mode mode-line + indicator is set to `TEMPORARY ONLY'. + +Non-interactively, turn temporary bookmarking on if and only if ARG is +positive. Non-interactively there is no prompt for confirmation." + :init-value nil :global t :group 'bookmark-plus :lighter bmkp-temporary-bookmarking-mode-lighter + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +Bookmark bug: \ +&body=Describe bug here, starting with `emacs -Q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Download" "https://www.emacswiki.org/emacs/download/bookmark%2b.el") + :link '(url-link :tag "Description" "https://www.emacswiki.org/emacs/BookmarkPlus") + :link '(emacs-commentary-link :tag "Commentary" "bookmark+") + (cond ((not bmkp-temporary-bookmarking-mode) ; Turn off. + (when (fboundp 'bmkp-unlight-bookmarks) ; In `bookmark+-lit.el'. + (bmkp-unlight-bookmarks ; Unhighlight the temporary (current) bookmarks. + '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays) nil)) + (bmkp-switch-to-last-bookmark-file) + (setq bmkp-last-bookmark-file bmkp-current-bookmark-file) ; Forget last (temp file). + (when (interactive-p) + (message "Bookmarking is NOT temporary now. Restored previous bookmarks list"))) + ((or (not (interactive-p)) + (y-or-n-p (format "%switch to only temporary bookmarking? " + (if bookmark-save-flag "Save current bookmarks, then s" "S")))) + (when (and (> bookmark-alist-modification-count 0) bookmark-save-flag) + (bookmark-save)) + (let ((new-file (make-temp-file "bmkp-temp-"))) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect new-file)) + (goto-char (point-min)) + (delete-region (point-min) (point-max)) ; In case a find-file hook inserted a header. + (if (boundp 'bookmark-file-coding-system) ; Emacs 25.2+ + (bookmark-insert-file-format-version-stamp bookmark-file-coding-system) + (bookmark-insert-file-format-version-stamp)) + (insert "(\n)")) + (bmkp-empty-file new-file) + (setq bmkp-last-as-first-bookmark-file nil) ; Prevent starting from a file of temp bmks. + (bookmark-load new-file t 'nosave) ; Saving was done just above. + (when bookmark-save-flag (bmkp-toggle-saving-bookmark-file (interactive-p)))) + (when (interactive-p) (message "Bookmarking is now TEMPORARY"))) + (t ; User refused to confirm. + (message "OK, canceled - bookmarking is NOT temporary") + (setq bmkp-temporary-bookmarking-mode nil))))) + + ;; Emacs 20 + (defun bmkp-temporary-bookmarking-mode (&optional arg) ; `M-L' in `*Bookmark List*'. + "Toggle temporary bookmarking. +Temporary bookmarking means that any bookmark changes (creation, +modification, deletion) are NOT automatically saved. + +Interactively, you are required to confirm turning on the mode. + +When the mode is turned ON: + a. `bookmark-save-flag' is set to nil. + b. `bmkp-current-bookmark-file' is set to a new, empty bookmark file + in directory `temporary-file-directory' (via `make-temp-file'). + c. That file is not saved automatically. + d. In the `*Bookmark List*' display, the major-mode mode-line + indicator is set to `TEMPORARY ONLY'. + +Non-interactively, turn temporary bookmarking on if and only if ARG is +positive. Non-interactively there is no prompt for confirmation." + (interactive "P") + (setq bmkp-temporary-bookmarking-mode + (if arg (> (prefix-numeric-value arg) 0) (not bmkp-temporary-bookmarking-mode))) + (cond ((not bmkp-temporary-bookmarking-mode) ; Turn off. + (when (fboundp 'bmkp-unlight-bookmarks) ; In `bookmark+-lit.el'. + (bmkp-unlight-bookmarks ; Unhighlight the temporary (current) bookmarks. + '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays) nil)) + (bmkp-switch-to-last-bookmark-file) + (setq bmkp-last-bookmark-file bmkp-current-bookmark-file) ; Forget last (temporary file). + (run-hooks 'bmkp-temporary-bookmarking-mode-hook) + (when (interactive-p) + (message "Bookmarking is NOT temporary now. Restored previous bookmarks list"))) + ((or (not (interactive-p)) + (y-or-n-p (format "%switch to only TEMPORARY bookmarking? " + (if bookmark-save-flag "Save current bookmarks, then s" "S")))) + (when (and (> bookmark-alist-modification-count 0) bookmark-save-flag) + (bookmark-save)) + (let ((new-file (make-temp-file "bmkp-temp-"))) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect new-file)) + (goto-char (point-min)) + (delete-region (point-min) (point-max)) ; In case a find-file hook inserted a header, etc. + (bookmark-insert-file-format-version-stamp) + (insert "(\n)")) + (bmkp-empty-file new-file) + (bookmark-load new-file t 'nosave) ; Saving was done just above. + (when bookmark-save-flag (bmkp-toggle-saving-bookmark-file (interactive-p)))) + (run-hooks 'bmkp-temporary-bookmarking-mode-hook) + (when (interactive-p) (message "Bookmarking is now TEMPORARY"))) + (t ; User refused to confirm. + (message "OK, canceled - bookmarking is NOT temporary") + (setq bmkp-temporary-bookmarking-mode nil)))) + + + (add-to-list 'minor-mode-alist `(bmkp-temporary-bookmarking-mode + ,bmkp-temporary-bookmarking-mode-lighter))) + +;;;###autoload (autoload 'bmkp-toggle-autotemp-on-set "bookmark+") +(defun bmkp-toggle-autotemp-on-set (&optional msg-p) ; Bound to `C-x x x' + "Toggle automatically making any bookmark temporary whenever it is set. +Non-interactively, non-nil MSG-P means display a status message." + (interactive "p") + (setq bmkp-autotemp-all-when-set-p (not bmkp-autotemp-all-when-set-p)) + (when msg-p (message "Automatically making bookmarks temporary when set is now %s" + (if bmkp-autotemp-all-when-set-p "ON" "OFF")))) + +;;;###autoload (autoload 'bmkp-toggle-temporary-bookmark "bookmark+") +(defun bmkp-toggle-temporary-bookmark (bookmark &optional msg-p) + "Toggle whether BOOKMARK is temporary (not saved to disk). +Return the full updated bookmark. +BOOKMARK is a bookmark name or a bookmark record. +Non-interactively, non-nil MSG-P means display a status message." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) 'MSG)) + (let ((was-temp (bmkp-temporary-bookmark-p bookmark))) + (bookmark-prop-set bookmark 'bmkp-temp (not was-temp)) + (when msg-p (message "Bookmark `%s' is now %s" + (if (stringp bookmark) bookmark (bmkp-bookmark-name-from-record bookmark)) + (if was-temp "SAVABLE" "TEMPORARY")))) + bookmark) + +;;;###autoload (autoload 'bmkp-make-bookmark-temporary "bookmark+") +(defun bmkp-make-bookmark-temporary (bookmark &optional msg-p) + "Make BOOKMARK temporary (not saved to disk). +Return the full updated bookmark. +BOOKMARK is a bookmark name or a bookmark record. +Non-interactively, non-nil MSG-P means display a status message." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) 'MSG)) + (bookmark-prop-set bookmark 'bmkp-temp t) + (when msg-p (message "Bookmark `%s' is now TEMPORARY" + (if (stringp bookmark) bookmark (bmkp-bookmark-name-from-record bookmark)))) + bookmark) + +;;;###autoload (autoload 'bmkp-make-bookmark-savable "bookmark+") +(defun bmkp-make-bookmark-savable (bookmark &optional msg-p) + "Make BOOKMARK savable to disk (not temporary). +Return the full updated bookmark. +BOOKMARK is a bookmark name or a bookmark record. +Non-interactively, non-nil MSG-P means display a status message." + (interactive (list (bookmark-completing-read "Bookmark" (bmkp-default-bookmark-name)) 'MSG)) + (bookmark-prop-set bookmark 'bmkp-temp nil) + (when msg-p (message "Bookmark `%s' is now SAVABLE" + (if (stringp bookmark) bookmark (bmkp-bookmark-name-from-record bookmark)))) + bookmark) + +;;;###autoload (autoload 'bmkp-delete-all-temporary-bookmarks "bookmark+") +(defun bmkp-delete-all-temporary-bookmarks (&optional msg-p) + "Delete all temporary bookmarks, after confirmation. +These are bookmarks that are `bmkp-temporary-bookmark-p'. You can +make a bookmark temporary using `bmkp-make-bookmark-temporary' or +`bmkp-toggle-temporary-bookmark'. +Non-interactively, non-nil MSG-P means display a status message." + (interactive "p") + (let ((bmks-to-delete (mapcar #'bmkp-bookmark-name-from-record (bmkp-temporary-alist-only)))) + (if (null bmks-to-delete) + (when msg-p (message "No temporary bookmarks to delete")) + (when (and msg-p (not (y-or-n-p (format "Delete ALL temporary bookmarks? ")))) + (error "OK - delete canceled")) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk bmks-to-delete) (bookmark-delete bmk 'BATCHP))) ; No refresh yet. + (bmkp-refresh/rebuild-menu-list nil (not msg-p)) ; Now refresh, after iterate. + (when msg-p (message "Deleted all temporary bookmarks"))))) + +;; You can use this in `kill-emacs-hook'. +(defun bmkp-delete-temporary-no-confirm () + "Delete all temporary bookmarks, without confirmation." + (when (and bookmarks-already-loaded bookmark-alist) + (let ((bmks-to-delete (mapcar #'bmkp-bookmark-name-from-record (bmkp-temporary-alist-only))) + (bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk bmks-to-delete) (bookmark-delete bmk 'BATCHP))) ; No refresh yet. + (bmkp-refresh/rebuild-menu-list nil 'BATCHP))) ; Now refresh, after iterate. + +;;;###autoload (autoload 'bmkp-delete-bookmarks "bookmark+") +(defun bmkp-delete-bookmarks (&optional position allp alist msg-p) ; Bound to `C-x x delete' + "Delete some bookmarks at point or all bookmarks in the buffer. +With no prefix argument, delete some bookmarks at point. +If there is more than one, require confirmation for each. + +With a prefix argument, delete *ALL* bookmarks in the current buffer. + +Non-interactively: +* Delete at POSITION, not point. If nil, delete at point. +* Non-nil optional arg ALLP means delete all bookmarks in the buffer. +* ALIST is the alist of bookmarks. + If nil, use the bookmarks in the current buffer. +* Non-nil MSG-P means display informative messages." + (interactive "d\nP\ni\np") + (unless position (setq position (point))) + (let ((bmks-to-delete (and allp (mapcar #'bmkp-bookmark-name-from-record (bmkp-this-buffer-alist-only)))) + (bmks-deleted ()) + bmk-pos) + (when (and msg-p bmks-to-delete (not (y-or-n-p (format "Delete ALL bookmarks in buffer `%s'? " + (buffer-name))))) + (error "Canceled - no bookmarks deleted")) + (cond (bmks-to-delete ; Delete all. + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bname bmks-to-delete) (bookmark-delete bname 'BATCHP))) ; No refresh yet. + (bmkp-refresh/rebuild-menu-list nil (not msg-p)) ; Refresh now, after iterate. + (when msg-p (message "Deleted all bookmarks in buffer `%s'" (buffer-name)))) + + (allp ; Requested ALLP, but there are none. (No-op if not interactive.) + (when msg-p (message "No bookmarks to delete in buffer `%s'" (buffer-name)))) + + (t ; Delete selected bookmarks at point. + (let (bname) + (dolist (bmk (or alist (bmkp-this-buffer-alist-only))) + (when (eq position (setq bmk-pos (bookmark-get-position bmk))) + (setq bname (bmkp-bookmark-name-from-record bmk)) + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bname bmks-to-delete) + (setq bmks-to-delete (cons bname bmks-to-delete))))) + (cond ((cadr bmks-to-delete) ; More than one at point. + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bname bmks-to-delete) + (when (or (not msg-p) (y-or-n-p (format "Delete bookmark `%s'? " bname))) + (bookmark-delete bname 'BATCHP) ; No refresh yet. + ;; This is the same as `add-to-list' with `EQ' (not available for Emacs 20-21). + (unless (memq bname bmks-deleted) (setq bmks-deleted (cons bname bmks-deleted)))))) + (bmkp-refresh/rebuild-menu-list nil (not msg-p)) ; Refresh now. + (when msg-p + (message (if bmks-deleted + (format "Deleted bookmarks: %s" + (mapconcat (lambda (bname) (format "`%s'" bname)) bmks-deleted + ", ")) + "No bookmarks deleted")))) + (bmks-to-delete ; Only one bookmark at point. + (bookmark-delete (car bmks-to-delete)) + (when msg-p (message "Deleted bookmark `%s'" (car bmks-to-delete)))) + (t + (when msg-p (message "No bookmarks at point to delete"))))))))) + +;; Because of Emacs bug #19915, we need to use `advice-add' for `org-store-link', so this feature +;; is available only for Emacs 24.4+. +(when (fboundp 'advice-add) + + (defvar bmkp-store-org-link-checking-p nil + "Whether `bmkp-(bmenu-)store-org-link(-1)' call is checking applicability.") + + (defun bmkp-store-org-link (arg) + "Store a link to a bookmark for insertion in an Org-mode buffer. +You are prompted for the bookmark name. + +If you use a numeric prefix arg then the bookmark will be jumped to in +the same window. Without a numeric prefix arg, the link will use +another window. The link type is `bookmark' or `bookmark-other-win', +respectively." + (interactive "P") + (require 'org) + (let ((org-store-link-functions (append org-store-link-functions '(bmkp-store-org-link-1)))) + (call-interactively #'org-store-link))) + + (defun bmkp-store-org-link-1 () + "Store a link to a bookmark for insertion in an Org-mode buffer. +See command `bmkp-store-org-link'." + (setq bmkp-store-org-link-checking-p (not bmkp-store-org-link-checking-p)) + (require 'org) + (or bmkp-store-org-link-checking-p ; Non-nil return is all that is needed for checking. + (let* ((other-win (and current-prefix-arg (not (consp current-prefix-arg)))) + (bmk (bmkp-completing-read-lax + (format "Store %sOrg link for bookmark" (if other-win "other-window " "")))) + (link (format "bookmark%s:%s" (if other-win "-other-win" "") bmk)) + (bmk-desc (format "Bookmark: %s" bmk))) + (org-store-link-props :type "bookmark" :link link :description bmk-desc)))) + + (advice-add 'org-store-link :before #'bmkp-reset-bmkp-store-org-link-checking-p) + (defun bmkp-reset-bmkp-store-org-link-checking-p (&rest _IGNORE) + "Reset `bmkp-store-org-link-checking-p' to nil." + (setq bmkp-store-org-link-checking-p nil))) + +(defun bmkp-ffap-guesser () + "`ffap-guesser', but deactivate a large active region first." + (and (require 'ffap nil t) + ;; Prevent using a large active region to guess ffap: Emacs bug #25243. + (let ((mark-active (and mark-active (< (buffer-size) bmkp-ffap-max-region-size)))) + (ffap-guesser)))) + +;; Same as `icicle-thing-at-point'. +(defun bmkp-thing-at-point (thing &optional syntax-table) + "`thingatpt+.el' version of `thing-at-point', if possible. +`tap-thing-at-point' if defined, else `thing-at-point'. +if non-nil, set SYNTAX-TABLE for the duration." + (if (fboundp 'tap-thing-at-point) + (tap-thing-at-point thing syntax-table) + (if (and (syntax-table-p syntax-table) (fboundp 'with-syntax-table)) ; Emacs 21+. + (with-syntax-table syntax-table (thing-at-point thing)) + (thing-at-point thing)))) ; Ignore any SYNTAX-TABLE arg for Emacs 20, for vanilla. + +(defun bmkp-get-external-annotation (annotation) + "Return a cons (DESTINATION . TYPE) for ANNOTATION. +DESTINATION is a string naming a file, a URL, or a bookmark. +TYPE is `FILE', `URL', or `BOOKMARK', accordingly." + (cond ((string-match "\\`\\s-*bmkp-annot-file:\\s-*\"\\(\.+\\)\"" annotation) + (cons (match-string 1 annotation) 'FILE)) + ((string-match "\\`\\s-*bmkp-annot-url:\\s-*\"\\(\.+\\)\"" annotation) + (cons (match-string 1 annotation) 'URL)) + ((string-match "\\`\\s-*bmkp-annot-bmk:\\s-*\"\\(\.+\\)\"" annotation) + (cons (match-string 1 annotation) 'BOOKMARK)) + (t nil))) + +(defun bmkp-visit-external-annotation (annotation.type msg-p) + "Visit the external annotation represented by ANNOTATION.TYPE. +The first arg is a cons as returned by `bmkp-get-external-annotation'. +I MSG-P is non-nil then echo the annotation type." + (let ((ann (car annotation.type)) + (type (cdr annotation.type))) + (case type + (FILE (find-file-other-window ann)) + (URL (browse-url ann)) + (BOOKMARK (bookmark-jump-other-window ann)) + (otherwise (error "`bmkp-visit-external-annotation': Bad annotation type: `%S'" type))) + (message "Showing external annotation of type %s" type) (sit-for 1))) + +;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'bookmark+-1) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-1.el ends here diff --git a/lisp/bookmark+-bmu.el b/lisp/bookmark+-bmu.el new file mode 100644 index 00000000..9fe5a12e --- /dev/null +++ b/lisp/bookmark+-bmu.el @@ -0,0 +1,6777 @@ +;;; bookmark+-bmu.el --- Bookmark+ code for the `*Bookmark List*' (bmenu). +;; +;; Filename: bookmark+-bmu.el +;; Description: Bookmark+ code for the `*Bookmark List*' (bmenu). +;; Author: Drew Adams, Thierry Volpiatto +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2000-2022, Drew Adams, all rights reserved. +;; Copyright (C) 2009, Thierry Volpiatto, all rights reserved. +;; Created: Mon Jul 12 09:05:21 2010 (-0700) +;; Last-Updated: Fri Jan 14 12:40:58 2022 (-0800) +;; By: dradams +;; Update #: 4177 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-bmu.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+, placeholders, annotations, search, info, url, eww, w3m, gnus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; `apropos', `apropos+', `avoid', `backquote', `bookmark', +;; `bookmark+', `bookmark+-1', `bookmark+-bmu', `bookmark+-key', +;; `bookmark+-lit', `button', `bytecomp', `cconv', `cl', `cl-lib', +;; `cmds-menu', `col-highlight', `crosshairs', `fit-frame', +;; `font-lock', `font-lock+', `frame-fns', `gv', `help+', +;; `help-fns', `help-fns+', `help-macro', `help-macro+', +;; `help-mode', `hl-line', `hl-line+', `info', `info+', `kmacro', +;; `macroexp', `menu-bar', `menu-bar+', `misc-cmds', `misc-fns', +;; `naked', `pp', `pp+', `radix-tree', `rect', `replace', +;; `second-sel', `strings', `syntax', `text-mode', `thingatpt', +;; `thingatpt+', `vline', `w32browser-dlgopen', `wid-edit', +;; `wid-edit+'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This library contains code for buffer `*Bookmark List*' (mode +;; `bookmark-bmenu-mode'). +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) library +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit.el' - (optional) code for highlighting bookmarks +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (this file) +;; `bookmark+-1.el' - other required code (non-bmenu) +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc.el' - documentation (comment-only file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you have library +;; `bookmark+-doc.el' in your `load-path'.) + +;;(@> "Index") +;; +;; Index +;; ----- +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "Things Defined Here") +;; (@> "Utility Functions") +;; (@> "Faces (Customizable)") +;; (@> "User Options (Customizable)") +;; (@> "Internal Variables") +;; (@> "Compatibility Code for Older Emacs Versions") +;; (@> "Menu List Replacements (`bookmark-bmenu-*')") +;; (@> "Bookmark+ Functions (`bmkp-*')") +;; (@> "Menu-List (`*-bmenu-*') Filter Commands") +;; (@> "Menu-List (`*-bmenu-*') Commands Involving Marks") +;; (@> "Omitted Bookmarks") +;; (@> "Search-and-Replace Locations of Marked Bookmarks") +;; (@> "Tags") +;; (@> "General Menu-List (`-*bmenu-*') Commands and Functions") +;; (@> "Sorting - Commands") +;; (@> "Other Bookmark+ Functions (`bmkp-*')") +;; (@> "Keymaps") + +;;(@* "Things Defined Here") +;; +;; Things Defined Here +;; ------------------- +;; +;; Commands defined here: +;; +;; `bmkp-bmenu-add-tags', `bmkp-bmenu-add-tags-to-marked', +;; `bmkp-bmenu-change-sort-order', +;; `bmkp-bmenu-change-sort-order-repeat', +;; `bmkp-bmenu-clone-bookmark', `bmkp-bmenu-copy-bookmark', +;; `bmkp-bmenu-copy-marked-to-bookmark-file', +;; `bmkp-bmenu-copy-tags', +;; `bmkp-bmenu-create-bookmark-file-from-marked', +;; `bmkp-bmenu-define-command', +;; `bmkp-bmenu-define-full-snapshot-command', +;; `bmkp-bmenu-define-jump-marked-command', +;; `bmkp-bmenu-delete-marked', `bmkp-bmenu-describe-marked', +;; `bmkp-bmenu-describe-this+move-down', +;; `bmkp-bmenu-describe-this+move-up', +;; `bmkp-bmenu-describe-this-bookmark',`bmkp-bmenu-dired-marked', +;; `bmkp-bmenu-edit-annotations-for-marked', +;; `bmkp-bmenu-edit-bookmark-name-and-location', +;; `bmkp-bmenu-filter-annotation-incrementally', +;; `bmkp-bmenu-filter-bookmark-name-incrementally', +;; `bmkp-bmenu-filter-file-name-incrementally', +;; `bmkp-bmenu-filter-tags-incrementally', +;; `bmkp-bmenu-flag-for-deletion', +;; `bmkp-bmenu-flag-for-deletion-backwards', +;; `bmkp-bmenu-isearch-marked-bookmarks' (Emacs 23+), +;; `bmkp-bmenu-isearch-marked-bookmarks-regexp' (Emacs 23+), +;; `bmkp-bmenu-jump-to-marked', `bmkp-bmenu-load-marking', +;; `bmkp-bmenu-load-marking-unmark-first', +;; `bmkp-bmenu-make-sequence-from-marked', `bmkp-bmenu-mark-all', +;; `bmkp-bmenu-mark-autofile-bookmarks', +;; `bmkp-bmenu-mark-bookmark-file-bookmarks', +;; `bmkp-bmenu-mark-bookmark-list-bookmarks', +;; `bmkp-bmenu-mark-bookmarks-satisfying', +;; `bmkp-bmenu-mark-bookmarks-tagged-all', +;; `bmkp-bmenu-mark-bookmarks-tagged-none', +;; `bmkp-bmenu-mark-bookmarks-tagged-not-all', +;; `bmkp-bmenu-mark-bookmarks-tagged-regexp', +;; `bmkp-bmenu-mark-bookmarks-tagged-some', +;; `bmkp-bmenu-mark-desktop-bookmarks', +;; `bmkp-bmenu-mark-dired-bookmarks', +;; `bmkp-bmenu-mark-eww-bookmarks' (Emacs 25+), +;; `bmkp-bmenu-mark-file-bookmarks', +;; `bmkp-bmenu-mark-function-bookmarks', +;; `bmkp-bmenu-mark-gnus-bookmarks', +;; `bmkp-bmenu-mark-icicles-search-hits-bookmarks', +;; `bmkp-bmenu-mark-image-bookmarks', +;; `bmkp-bmenu-mark-info-bookmarks', +;; `bmkp-bmenu-mark-lighted-bookmarks', +;; `bmkp-bmenu-mark-man-bookmarks', +;; `bmkp-bmenu-mark-non-file-bookmarks', +;; `bmkp-bmenu-mark-non-invokable-bookmarks', +;; `bmkp-bmenu-mark-orphaned-local-file-bookmarks', +;; `bmkp-bmenu-mark-region-bookmarks', +;; `bmkp-bmenu-mark-snippet-bookmarks', +;; `bmkp-bmenu-mark-specific-buffer-bookmarks', +;; `bmkp-bmenu-mark-specific-file-bookmarks', +;; `bmkp-bmenu-mark-url-bookmarks', +;; `bmkp-bmenu-mark-variable-list-bookmarks', +;; `bmkp-bmenu-mark-w3m-bookmarks', `bmkp-bmenu-mouse-3-menu', +;; `bmkp-bmenu-mode-status-help', +;; `bmkp-bmenu-move-marked-to-bookmark-file', +;; `bmkp-bmenu-nb-marked-in-mode-name', `bmkp-bmenu-omit', +;; `bmkp-bmenu-omit-marked', `bmkp-bmenu-omit/unomit-marked', +;; `bmkp-bmenu-paste-add-tags', +;; `bmkp-bmenu-paste-add-tags-to-marked', +;; `bmkp-bmenu-paste-replace-tags', +;; `bmkp-bmenu-paste-replace-tags-for-marked', +;; `bmkp-bmenu-query-replace-marked-bookmarks-regexp', +;; `bmkp-bmenu-quit', `bmkp-bmenu-refresh-menu-list', +;; `bmkp-bmenu-regexp-mark', `bookmark-bmenu-relocate' (Emacs 20, +;; 21), `bmkp-bmenu-relocate-marked', `bmkp-bmenu-remove-all-tags', +;; `bmkp-bmenu-remove-tags', `bmkp-bmenu-remove-tags-from-marked', +;; `bmkp-bmenu-search-marked-bookmarks-regexp', +;; `bmkp-bmenu-set-bookmark-file-bookmark-from-marked', +;; `bmkp-bmenu-set-tag-value', +;; `bmkp-bmenu-set-tag-value-for-marked', `bmkp-bmenu-show-all', +;; `bmkp-bmenu-show-only-autofile-bookmarks', +;; `bmkp-bmenu-show-only-autonamed-bookmarks', +;; `bmkp-bmenu-show-only-bookmark-file-bookmarks', +;; `bmkp-bmenu-show-only-bookmark-list-bookmarks', +;; `bmkp-bmenu-show-only-desktop-bookmarks', +;; `bmkp-bmenu-show-only-dired-bookmarks', +;; `bmkp-bmenu-show-only-eww-bookmarks' (Emacs 25+), +;; `bmkp-bmenu-show-only-file-bookmarks', +;; `bmkp-bmenu-show-only-function-bookmarks', +;; `bmkp-bmenu-show-only-gnus-bookmarks', +;; `bmkp-bmenu-show-only-icicles-search-hits-bookmarks.', +;; `bmkp-bmenu-show-only-image-bookmarks', +;; `bmkp-bmenu-show-only-info-bookmarks', +;; `bmkp-bmenu-show-only-man-bookmarks', +;; `bmkp-bmenu-show-only-non-file-bookmarks', +;; `bmkp-bmenu-show-only-non-invokable-bookmarks', +;; `bmkp-bmenu-show-only-omitted-bookmarks', +;; `bmkp-bmenu-show-only-orphaned-local-file-bookmarks', +;; `bmkp-bmenu-show-only-region-bookmarks', +;; `bmkp-bmenu-show-only-snippet-bookmarks', +;; `bmkp-bmenu-show-only-specific-buffer-bookmarks', +;; `bmkp-bmenu-show-only-specific-file-bookmarks', +;; `bmkp-bmenu-show-only-temporary-bookmarks', +;; `bmkp-bmenu-show-only-tagged-bookmarks', +;; `bmkp-bmenu-show-only-untagged-bookmarks', +;; `bmkp-bmenu-show-only-url-bookmarks', +;; `bmkp-bmenu-show-only-variable-list-bookmarks', +;; `bmkp-bmenu-show-only-w3m-bookmarks', +;; `bmkp-bmenu-show-or-edit-annotation', +;; `bmkp-bmenu-show-this-annotation+move-down', +;; `bmkp-bmenu-show-this-annotation+move-up', +;; `bmkp-bmenu-sort-annotated-before-unannotated', +;; `bmkp-bmenu-sort-by-bookmark-name', +;; `bmkp-bmenu-sort-by-bookmark-visit-frequency', +;; `bmkp-bmenu-sort-by-bookmark-type', +;; `bmkp-bmenu-sort-by-creation-time', +;; `bmkp-bmenu-sort-by-file-name', +;; `bmkp-bmenu-sort-by-Gnus-thread', +;; `bmkp-bmenu-sort-by-Info-node-name', +;; `bmkp-bmenu-sort-by-Info-position', +;; `bmkp-bmenu-sort-by-last-bookmark-access', +;; `bmkp-bmenu-sort-by-last-buffer-or-file-access', +;; `bmkp-bmenu-sort-by-last-local-file-access', +;; `bmkp-bmenu-sort-by-last-local-file-update', +;; `bmkp-bmenu-sort-by-local-file-size', +;; `bmkp-bmenu-sort-by-local-file-type', `bmkp-bmenu-sort-by-url', +;; `bmkp-bmenu-sort-flagged-before-unflagged', +;; `bmkp-bmenu-sort-marked-before-unmarked', +;; `bmkp-bmenu-sort-modified-before-unmodified', +;; `bmkp-bmenu-sort-tagged-before-untagged', +;; `bmkp-bmenu-toggle-marked-temporary/savable', +;; `bmkp-bmenu-toggle-marks', `bmkp-bmenu-toggle-show-only-marked', +;; `bmkp-bmenu-toggle-show-only-unmarked', +;; `bmkp-bmenu-toggle-temporary', `bmkp-bmenu-unmark-all', +;; `bmkp-bmenu-unmark-bookmarks-tagged-all', +;; `bmkp-bmenu-unmark-bookmarks-tagged-none', +;; `bmkp-bmenu-unmark-bookmarks-tagged-not-all', +;; `bmkp-bmenu-unmark-bookmarks-tagged-regexp', +;; `bmkp-bmenu-unmark-bookmarks-tagged-some', +;; `bmkp-bmenu-unomit-marked', `bmkp-bmenu-w32-open', +;; `bmkp-bmenu-w32-open-select', `bmkp-bmenu-w32-open-with-mouse', +;; `bmkp-define-tags-sort-command'. +;; +;; Faces defined here: +;; +;; `bmkp-*-mark', `bmkp->-mark', `bmkp-a-mark', +;; `bmkp-bad-bookmark', `bmkp-bookmark-file', `bmkp-bookmark-list', +;; `bmkp-buffer', `bmkp-D-mark', `bmkp-desktop', +;; `bmkp-file-handler', `bmkp-function', `bmkp-gnus', +;; `bmkp-heading', `bmkp-info', `bmkp-local-directory', +;; `bmkp-local-file-with-region', `bmkp-local-file-without-region', +;; `bmkp-man', `bmkp-no-jump', `bmkp-no-local', `bmkp-non-file', +;; `bmkp-remote-file', `bmkp-sequence', `bmkp-snippet', +;; `bmkp-su-or-sudo', `bmkp-t-mark', `bmkp-url', +;; `bmkp-variable-list', `bmkp-X-mark'. +;; +;; User options defined here: +;; +;; `bmkp-bmenu-commands-file', +;; `bmkp-bmenu-image-bookmark-icon-file', +;; `bmkp-bmenu-omitted-bookmarks', `bmkp-bmenu-state-file', +;; `bmkp-propertize-bookmark-names-flag', `bmkp-sort-orders-alist', +;; `bmkp-sort-orders-for-cycling-alist'. +;; +;; Non-interactive functions defined here: +;; +;; `bmkp--pop-to-buffer-same-window', `bmkp-assoc-delete-all', +;; `bmkp-bmenu-barf-if-not-in-menu-list', +;; `bmkp-bmenu-cancel-incremental-filtering', +;; `bmkp-bmenu-filter-alist-by-annotation-regexp', +;; `bmkp-bmenu-filter-alist-by-bookmark-name-regexp', +;; `bmkp-bmenu-filter-alist-by-file-name-regexp', +;; `bmkp-bmenu-filter-alist-by-tags-regexp', +;; `bmkp-bmenu-get-marked-files', `bmkp-bmenu-goto-bookmark-named', +;; `bmkp-bmenu-kill-annotation', `bmkp-bmenu-list-1', +;; `bmkp-bmenu-mark/unmark-bookmarks-tagged-all/none', +;; `bmkp-bmenu-mark/unmark-bookmarks-tagged-some/not-all', +;; `bmkp-bmenu-mode-line', `bmkp-bmenu-mode-line-string', +;; `bmkp-bmenu-propertize-item', `bmkp-bmenu-read-filter-input', +;; `bmkp-bmenu-store-org-link' (Emacs 24.4+), +;; `bmkp-bookmark-data-from-record', +;; `bmkp-bookmark-name-from-record', `bmkp-face-prop', +;; `bmkp-bmenu-marked-or-this-or-all', `bmkp-looking-at-p', +;; `bmkp-maybe-unpropertize-bookmark-names', +;; `bmkp-maybe-unpropertize-string', `bmkp-remap', +;; `bmkp-replace-regexp-in-string', +;; `bmkp-reverse-multi-sort-order', `bmkp-reverse-sort-order', +;; `bmkp-string-match-p', `bookmark-name-from-full-record', +;; `bookmark-name-from-record', +;; +;; Internal variables defined here: +;; +;; `bmkp-bmenu-before-hide-marked-alist', +;; `bmkp-bmenu-before-hide-unmarked-alist', +;; `bmkp-bmenu-bookmark-file-menu', +;; `bmkp-bmenu-define-command-history', +;; `bmkp-bmenu-define-command-menu', `bmkp-bmenu-delete-menu', +;; `bmkp-bmenu-filter-function', `bmkp-bmenu-filter-pattern', +;; `bmkp-bmenu-filter-timer', `bmkp-bmenu-first-time-p', +;; `bmkp-bmenu-header-lines', `bmkp-bmenu-highlight-menu', +;; `bmkp-bmenu-line-overlay', `bmkp-bmenu-mark-menu', +;; `bmkp-bmenu-marked-bookmarks', `bmkp-bmenu-marks-width', +;; `bmkp-bmenu-mark-types-menu', `bmkp-bmenu-menubar-menu', +;; `bmkp-bmenu-omit-menu', `bmkp-bmenu-search-menu', +;; `bmkp-bmenu-show-menu', +;; `bmkp-bmenu-show-types-menu',`bmkp-bmenu-sort-menu', +;; `bmkp-bmenu-tags-menu', `bmkp-bmenu-title', +;; `bmkp-bmenu-toggle-menu', `bmkp-flagged-bookmarks', +;; `bmkp-last-bmenu-bookmark'. +;; +;; +;; ***** NOTE: The following commands defined in `bookmark.el' +;; have been REDEFINED HERE: +;; +;; `bookmark-bmenu-execute-deletions', `bookmark-bmenu-list', +;; `bookmark-bmenu-mark', `bookmark-bmenu-1-window', +;; `bookmark-bmenu-2-window', `bookmark-bmenu-other-frame', +;; `bookmark-bmenu-other-window', +;; `bookmark-bmenu-other-window-with-mouse', +;; `bookmark-bmenu-rename', `bookmark-bmenu-show-annotation', +;; `bookmark-bmenu-switch-other-window', +;; `bookmark-bmenu-this-window', `bookmark-bmenu-toggle-filenames', +;; `bookmark-bmenu-unmark'. +;; +;; +;; ***** NOTE: The following non-interactive functions and macros +;; defined in `bookmark.el' have been REDEFINED HERE: +;; +;; `bookmark-bmenu-bookmark', `bookmark-bmenu-check-position', +;; `bookmark-bmenu-delete', `bookmark-bmenu-delete-backwards', +;; `bookmark-bmenu-ensure-position' (Emacs 23.2+), +;; `bookmark-bmenu-hide-filenames', `bookmark-bmenu-mode', +;; `bookmark-bmenu-show-filenames', +;; `bookmark-bmenu-surreptitiously-rebuild-list', +;; `with-buffer-modified-unmodified' (Emacs < 23.2). +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;; + +(eval-when-compile (require 'cl)) ;; case (plus, for Emacs 20: dolist, push) +(eval-when-compile (require 'easymenu)) ;; easy-menu-create-menu +(eval-when-compile (require 'org nil t)) ;; org-add-link-type + +(require 'bookmark) +;; bookmark-alist, bookmark-bmenu-file-column, +;; bookmark-bmenu-hidden-bookmarks, bookmark-bmenu-mode-map, +;; bookmark-bmenu-select, bookmark-get-annotation, +;; bookmark-get-filename, bookmark-get-handler, bookmark-kill-line, +;; bookmark-maybe-load-default-file, bookmark-name-from-full-record, +;; bookmark-name-from-record, bookmark-prop-get + + +;; Some general Renamings. +;; +;; 1. Fix incompatibility introduced by gratuitous Emacs name change. +;; +(cond ((and (fboundp 'bookmark-name-from-record) (not (fboundp 'bookmark-name-from-full-record))) + (defalias 'bookmark-name-from-full-record 'bookmark-name-from-record)) + ((and (fboundp 'bookmark-name-from-full-record) (not (fboundp 'bookmark-name-from-record))) + (defalias 'bookmark-name-from-record 'bookmark-name-from-full-record))) + +;; 2. The vanilla name of the first is misleading, as it returns only the cdr of the record. +;; The second is for consistency. +;; +(defalias 'bmkp-bookmark-data-from-record 'bookmark-get-bookmark-record) +(defalias 'bmkp-bookmark-name-from-record 'bookmark-name-from-full-record) + + +(eval-when-compile + (or (condition-case nil + (load-library "bookmark+-mac") ; Use load-library to ensure latest .elc. + (error nil)) + (require 'bookmark+-mac))) ; Require, so can load separately if not on `load-path'. +;; bmkp-define-show-only-command, bmkp-define-sort-command, bmkp-menu-bar-make-toggle, +;; bmkp-with-help-window, bmkp-with-output-to-plain-temp-buffer + +(put 'bmkp-with-output-to-plain-temp-buffer 'common-lisp-indent-function '(4 &body)) + + +;;; These functions are used in macro `bmkp-define-sort-command'. The first is used in the macro code +;;; that produces the function code, so its definition is also in `bookmark+-mac.el'. +;;; +(defun bmkp-replace-regexp-in-string (regexp rep string &optional fixedcase literal subexp start) + "Replace all matches for REGEXP with REP in STRING and return STRING." + (if (fboundp 'replace-regexp-in-string) ; Emacs > 20. + (replace-regexp-in-string regexp rep string fixedcase literal subexp start) + (if (string-match regexp string) (replace-match rep nil nil string) string))) ; Emacs 20 + +(defun bmkp-assoc-delete-all (key alist) + "Delete from ALIST all elements whose car is `equal' to KEY. +Return the modified alist. +Elements of ALIST that are not conses are ignored." + (while (and (consp (car alist)) (equal (car (car alist)) key)) (setq alist (cdr alist))) + (let ((tail alist) + tail-cdr) + (while (setq tail-cdr (cdr tail)) + (if (and (consp (car tail-cdr)) (equal (car (car tail-cdr)) key)) + (setcdr tail (cdr tail-cdr)) + (setq tail tail-cdr)))) + alist) + + +;; (eval-when-compile (require 'bookmark+-1)) + +;; bmkp-add-tags, bmkp-alpha-p, bmkp-bookmark-creation-cp, +;; bmkp-bookmark-description, bmkp-bookmark-file-bookmark-p, +;; bmkp-bookmark-last-access-cp, bmkp-bookmark-list-bookmark-p, +;; bmkp-buffer-last-access-cp, bmkp-completing-read-buffer-name, +;; bmkp-completing-read-file-name, bmkp-current-bookmark-file, +;; bmkp-current-sort-order, bmkp-describe-bookmark, +;; bmkp-describe-bookmark-internals, bmkp-desktop-bookmark-p, +;; bmkp-edit-bookmark-name-and-location, bmkp-file-alpha-cp, +;; bmkp-file-remote-p, bmkp-function-bookmark-p, bmkp-get-bookmark, +;; bmkp-get-buffer-name, bmkp-get-tags, bmkp-gnus-bookmark-p, +;; bmkp-gnus-cp, bmkp-handler-cp, bmkp-incremental-filter-delay, +;; bmkp-image-bookmark-p, bmkp-info-bookmark-p, +;; bmkp-info-node-name-cp, bmkp-info-position-cp, +;; bmkp-isearch-bookmarks, bmkp-isearch-bookmarks-regexp, bmkp-jump-1, +;; bmkp-last-bookmark-file, bmkp-last-specific-buffer, +;; bmkp-last-specific-file, bmkp-latest-bookmark-alist, +;; bmkp-local-file-bookmark-p, bmkp-local-file-type-cp, +;; bmkp-local-file-accessed-more-recently-cp, +;; bmkp-local-file-updated-more-recently-cp, +;; bmkp-set-sequence-bookmark, bmkp-man-bookmark-p, +;; bmkp-marked-bookmark-p, bmkp-marked-bookmarks-only, bmkp-marked-cp, +;; bmkp-msg-about-sort-order, bmkp-non-file-filename, +;; bmkp-read-tag-completing, bmkp-read-tags-completing, +;; bmkp-refresh-menu-list, bmkp-region-bookmark-p, +;; bmkp-remove-all-tags, bmkp-remove-if, bmkp-remove-tags, +;; bmkp-repeat-command, bmkp-reverse-multi-sort-p, +;; bmkp-reverse-sort-p, bmkp-root-or-sudo-logged-p, bmkp-same-file-p, +;; bmkp-save-menu-list-state, bmkp-sequence-bookmark-p, +;; bmkp-set-tag-value, bmkp-set-tag-value-for-bookmarks, +;; bmkp-set-union, bmkp-snippet-alist-only, bmkp-snippet-bookmark-p, +;; bmkp-some, bmkp-some-marked-p, bmkp-some-unmarked-p, +;; bmkp-sort-omit, bmkp-sort-comparer, bmkp-sorted-alist, +;; bmkp-su-or-sudo-regexp, bmkp-tag-name, bmkp-tags-list, +;; bmkp-url-bookmark-p, bmkp-url-cp, bmkp-unmarked-bookmarks-only, +;; bmkp-variable-list-bookmark-p, bmkp-visited-more-cp + +;; (eval-when-compile (require 'bookmark+-lit nil t)) +;; bmkp-get-lighting + +;;;;;;;;;;;;;;;;;;;;;;; + +;; Quiet the byte-compiler +(defvar bookmark-file-coding-system) ; In `bookmark.el' (Emacs 25.2+) +(defvar bmkp-bmenu-buffer) ; In `bookmark+.el' +(defvar bmkp-bmenu-highlight-menu) ; Defined in this file (conditionally). +(defvar bmkp-copied-tags) ; In `bookmark+-1.el'. +(defvar bmkp-count-multi-mods-as-one-flag) ; In `bookmark+-1.el'. +(defvar bmkp-current-bookmark-file) ; In `bookmark+-1.el'. +(defvar bmkp-edit-bookmark-orig-record) ; In `bookmark+-1.el'. +(defvar bmkp-incremental-filter-delay) ; In `bookmark+-1.el'. +(defvar bmkp-edit-bookmark-records-number) ; In `bookmark+-1.el'. +(defvar bmkp-last-bookmark-file) ; In `bookmark+-1.el'. +(defvar bmkp-last-specific-buffer) ; In `bookmark+-1.el'. +(defvar bmkp-last-specific-file) ; In `bookmark+-1.el'. +(defvar bmkp-latest-bookmark-alist) ; In `bookmark+-1.el'. +(defvar bmkp-modified-bookmarks) ; In `bookmark+-1.el'. +(defvar bmkp-non-file-filename) ; In `bookmark+-1.el'. +(defvar bmkp-reverse-multi-sort-p) ; In `bookmark+-1.el'. +(defvar bmkp-reverse-sort-p) ; In `bookmark+-1.el'. +(defvar bmkp-sort-comparer) ; In `bookmark+-1.el'. +(defvar bmkp-sorted-alist) ; In `bookmark+-1.el'. +(defvar bmkp-sort-orders-alist) ; Here. +(defvar bmkp-su-or-sudo-regexp) ; In `bookmark+-1.el'. +(defvar bmkp-temporary-bookmarking-mode) ; In `bookmark+-1.el'. +(defvar dired-re-mark) ; In `dired.el'. +(defvar icicle-candidate-properties-alist) ; In `icicles-var.el'. +(defvar minibuffer-prompt-properties) ; Emacs 22+. +(defvar tramp-file-name-regexp) ; In `tramp.el'. + + +;;(@* "Utility Functions") +;;; Utility Functions ------------------------------------------------ + +;; Same as `tap-string-match-p' in `thingatpt+.el' and `icicle-string-match-p' in `icicles-fn.el'. +(if (fboundp 'string-match-p) + (defalias 'bmkp-string-match-p 'string-match-p) ; Emacs 23+ + (defun bmkp-string-match-p (regexp string &optional start) + "Like `string-match', but this saves and restores the match data." + (save-match-data (string-match regexp string start)))) + +;; Same as `tap-looking-at-p' in `thingatpt+.el' and `icicle-looking-at-p' in `icicles-mcmd.el'. +;; Do not `defalias' to Emacs `looking-at-p' because that is a `defsubst'. +(defun bmkp-looking-at-p (regexp) + "Like `looking-at', but this saves and restores the match data." + (save-match-data (looking-at regexp))) + +;; Same as `icicle-remap' in `icicles-opt.el'. Not used yet. +(defun bmkp-remap (old new map &optional oldmap) + "Bind command NEW in MAP to all keys currently bound to OLD. +If command remapping is available, use that. Otherwise, bind NEW to +whatever OLD is bound to in MAP, or in OLDMAP, if provided." + (if (fboundp 'command-remapping) + (define-key map (vector 'remap old) new) ; Ignore OLDMAP for Emacs 22. + (substitute-key-definition old new map oldmap))) + +;; This is also in `bookmark+-lit.el', since it is loaded first but is optional. +;; +(if (fboundp 'pop-to-buffer-same-window) + (defalias 'bmkp--pop-to-buffer-same-window 'pop-to-buffer-same-window) + (defalias 'bmkp--pop-to-buffer-same-window 'switch-to-buffer)) + +;;(@* "Faces (Customizable)") +;;; Faces (Customizable) --------------------------------------------- + +(defface bmkp->-mark '((((background dark)) (:foreground "Yellow")) + (t (:foreground "Blue"))) + ;; (:foreground "Magenta2" :box (:line-width 1 :style pressed-button)))) + "*Face used for a `>' mark in the bookmark list." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-a-mark '((((background dark)) (:background "SaddleBrown")) + (t (:background "SkyBlue"))) + "*Face used for an annotation indicator (`a') in the bookmark list." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-bad-bookmark '((t (:foreground "Red" :background "Chartreuse1"))) + "*Face used for a bookmark that seems to be bad: e.g., nonexistent file." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-bookmark-file + '((((background dark)) + (:foreground "#00005A5AFFFF" :background "#FFFF9B9BFFFF")) ; ~ blue, ~ pink + (t (:foreground "Orange" :background "DarkGreen"))) + "*Face used for a bookmark-file bookmark." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-bookmark-list + '((((background dark)) (:foreground "#7474FFFFFFFF" :background "DimGray")) ; ~ cyan + (t (:foreground "DarkRed" :background "LightGray"))) + "*Face used for a bookmark-list bookmark." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-buffer + '((((background dark)) (:foreground "#FFFF9B9BFFFF")) ; ~ pink + (t (:foreground "DarkGreen"))) + "*Face used for a bookmarked existing buffer not associated with a file." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-D-mark '((t (:foreground "Yellow" :background "Red"))) + "*Face used for a deletion mark (`D') in the bookmark list." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-desktop + '((((background dark)) (:foreground "Orange" :background "DarkSlateBlue")) + (t (:foreground "DarkBlue" :background "PaleGoldenrod"))) + "*Face used for a bookmarked desktop." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-file-handler + '((((background dark)) (:background "#FFFF78CB48E1")) ; ~ dark brown + (t (:background "LightBlue"))) + "*Face used for a bookmark that has a `file-handler' attribute." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-function + '((((background dark)) (:foreground "#0000EBEB6C6C")) ; ~ green + (t (:foreground "DeepPink1"))) + "*Face used for a function bookmark: a bookmark that invokes a function." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-gnus + '((((background dark)) (:foreground "Gold")) + (t (:foreground "DarkBlue"))) + "*Face used for a Gnus bookmark." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-info + '((((background dark)) (:foreground "#7474FFFFFFFF")) ; ~ light cyan + (t (:foreground "DarkRed"))) + "*Face used for a bookmarked Info node." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-local-directory + '((((background dark)) + (:foreground "Pink" :background "DarkBlue")) + (t (:foreground "DarkBlue" :background "HoneyDew2"))) + "*Face used for a bookmarked local directory." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-local-file-without-region + '((((background dark)) (:foreground "White")) + (t (:foreground "Black"))) + "*Face used for a bookmarked local file (without a region)." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-local-file-with-region + '((((background dark)) (:foreground "Yellow")) + (t (:foreground "Blue"))) + "*Face used for a region bookmark in a local file." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-man + '((((background dark)) (:foreground "Orchid")) + (t (:foreground "Orange4"))) + "*Face used for a `man' page bookmark." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-*-mark '((t (:foreground "Red" :background "Yellow"))) + "*Face used for a modification mark (`*') in the bookmark list." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-no-jump + '((t (:foreground "gray50"))) + "*Face used for a bookmark you cannot jump to from `*Bookmark List*'." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-no-local + '((t (:background "orange"))) + "*Face used for a local file bookmark whose target file does not exist." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-non-file + '((t (:foreground "MediumSeaGreen"))) + "*Face used for a bookmark not associated with an existing buffer." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-remote-file + '((((background dark)) (:foreground "#6B6BFFFF2C2C")) ; ~ green + (t (:foreground "DarkViolet"))) + "*Face used for a bookmarked tramp remote file (/ssh:)." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-sequence + '((((background dark)) (:foreground "DeepSkyBlue")) + (t (:foreground "DarkOrange2"))) + "*Face used for a sequence bookmark: one composed of other bookmarks." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-snippet + (if (> emacs-major-version 21) + '((t (:inherit region))) + '((t (:background "MediumAquamarine")))) + "*Face used for a bookmarked snippet." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-su-or-sudo '((t (:foreground "Red"))) + "*Face used for a bookmarked tramp file (/su: or /sudo:)." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-t-mark '((((background dark)) (:foreground "Magenta")) + (t (:foreground "#000093F402A2"))) ; a medium green + "*Face used for a tags mark (`t') in the bookmark list." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-url + '((((background dark)) (:foreground "#7474FFFF7474")) ; ~ green + (t (:foreground "DarkMagenta"))) + "*Face used for a bookmarked URL." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-variable-list + '((((background dark)) (:foreground "#FFFF8D947477")) ; ~ salmon + (t (:foreground "#0000726B8B8B"))) ; ~dark cyan + "*Face used for a bookmarked list of variables." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-X-mark '((t (:foreground "Red"))) + "*Face used for a temporary-bookmark indicator (`X') in the bookmark list." + :group 'bookmark-plus :group 'faces) + +;; $$$$$$ Not used now - using `bmkp-url' instead. +;; (defface bmkp-w3m +;; '((((background dark)) (:foreground "yellow")) +;; (t (:foreground "DarkMagenta"))) +;; "*Face used for a bookmarked w3m url." +;; :group 'bookmark-plus :group 'faces) + +;; Instead of vanilla `bookmark-menu-heading' (defined in Emacs 22+), to use a better default. +(defface bmkp-heading '((((background dark)) (:foreground "Yellow")) + (t (:foreground "Blue"))) + "*Face used to highlight the headings in various Bookmark+ buffers." + :group 'bookmark-plus :version "22.1" :group 'faces) + +;;(@* "User Options (Customizable)") +;;; User Options (Customizable) -------------------------------------- + +;;;###autoload (autoload 'bmkp-bmenu-omitted-bookmarks "bookmark+") +(defcustom bmkp-bmenu-omitted-bookmarks () + "*List of names of omitted bookmarks. +They are generally not available for display in the bookmark list. +You can, however, use \\\ +`\\[bmkp-bmenu-show-only-omitted-bookmarks]' to see them. +You can then mark some of them and use `\\[bmkp-bmenu-omit/unomit-marked]' + to make those that are marked available again for the bookmark list." + ;; $$$$$$ TODO: Create a customize :type `bookmark-name' + ;; and provide completion for filling out the field. + :type '(repeat (string :tag "Bookmark name")) :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-bmenu-commands-file "bookmark+") +(defcustom bmkp-bmenu-commands-file (convert-standard-filename "~/.emacs-bmk-bmenu-commands.el") + "*File for saving user-defined bookmark-list commands. +This must be an absolute file name (possibly containing `~') or nil +\(it is not expanded). + +You can use `\\[bmkp-list-defuns-in-commands-file]' to list the +commands defined in the file and how many times each is defined. + +NOTE: Each time you define a command using \\\ +`\\[bmkp-bmenu-define-command]', `\\[bmkp-bmenu-define-full-snapshot-command]', \ +`\\[bmkp-bmenu-define-jump-marked-command], or `\\[bmkp-define-tags-sort-command]', +it is saved in the file. The new definition is simply appended to the +file - old definitions of the same command are not overwritten. So +you might want to clean up the file occasionally, to remove any old, +unused definitions. This is especially advisable if you used \ +`\\[bmkp-bmenu-define-full-snapshot-command]', +because such command definitions can be very large." + :type '(file :tag "File for saving menu-list state") :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-bmenu-state-file "bookmark+") +(defcustom bmkp-bmenu-state-file (convert-standard-filename "~/.emacs-bmk-bmenu-state.el") + "*File for saving `*Bookmark List*' state when you quit bookmark list. +This must be an absolute file name (possibly containing `~') or nil +\(it is not expanded). + +The state is also saved when you quit Emacs, even if you don't quit +the bookmark list first (using \\`\\[bmkp-bmenu-quit]'). + +Set this to nil if you do not want to restore the bookmark list as it +was the last time you used it." + :type '(choice + (const :tag "Do not save and restore menu-list state" nil) + (file :tag "File for saving menu-list state")) + :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-bmenu-image-bookmark-icon-file "bookmark+") +(defcustom bmkp-bmenu-image-bookmark-icon-file + (and (fboundp 'display-images-p) (display-images-p) + (let ((bmk-img (convert-standard-filename "~/.emacs-bmk-bmenu-image-file-icon.png")) + (emacs-img (convert-standard-filename (concat data-directory "images/gnus/exit-gnus.xpm")))) + (or (and (file-readable-p bmk-img) bmk-img) + (and (file-readable-p emacs-img) emacs-img)))) + "*Iconic image file to show next to image-file bookmarks. +If nil, show no image. Otherwise, this is an absolute file name, +possibly containing `~', (the value is not expanded). + +Use any image file that Emacs can display, but you probably want to +use a small, iconic image - say 16x16 pixels. + +The default image, which you are sure to have in any Emacs version +that supports images, is 24x24 pixels. That wastes vertical space, so +you probably want to use something smaller. + +If you don't have another image that you prefer, try this one (16x16): +https://www.emacswiki.org/emacs/BookmarkPlusImageFileDefaultIcon" + :type '(choice + (file :tag "Use iconic image file") + (const :tag "Show no image")) + :group 'bookmark-plus) + +;; This is a general option. It is in this file because it is used mainly by the bmenu code. +(when (> emacs-major-version 20) + (defcustom bmkp-sort-orders-alist () + "*Alist of all available sort functions. +This is a pseudo option - you probably do NOT want to customize this. +Instead: + + * To add a new sort function to this list, use macro + `bmkp-define-sort-command'. It defines a new sort function + and automatically adds it to this list. + + * To have fewer sort orders available for cycling by \\\ +`\\[bmkp-bmenu-change-sort-order-repeat]'..., + customize option `bmkp-sort-orders-for-cycling-alist'. + +Each alist element has the form (SORT-ORDER . COMPARER): + + SORT-ORDER is a short string or symbol describing the sort order. + Examples: \"by last access time\", \"by bookmark name\". + + COMPARER compares two bookmarks. It must be acceptable as a value of + `bmkp-sort-comparer'." + :type '(alist + :key-type (choice :tag "Sort order" string symbol) + :value-type (choice + (const :tag "None (do not sort)" nil) + (function :tag "Sorting Predicate") + (list :tag "Sorting Multi-Predicate" + (repeat (function :tag "Component Predicate")) + (choice + (const :tag "None" nil) + (function :tag "Final Predicate"))))) + :group 'bookmark-plus)) + +(unless (> emacs-major-version 20) ; Emacs 20: custom type `alist' doesn't exist. + (defcustom bmkp-sort-orders-alist () + "*Alist of all available sort functions. +This is a pseudo option - you probably do NOT want to customize this. +Instead: + + * To add a new sort function to this list, use macro + `bmkp-define-sort-command'. It defines a new sort function + and automatically adds it to this list. + + * To have fewer sort orders available for cycling by \\\ +`\\[bmkp-bmenu-change-sort-order-repeat]'..., + customize option `bmkp-sort-orders-for-cycling-alist'. + +Each alist element has the form (SORT-ORDER . COMPARER): + + SORT-ORDER is a short string or symbol describing the sort order. + Examples: \"by last access time\", \"by bookmark name\". + + COMPARER compares two bookmarks. It must be acceptable as a value of + `bmkp-sort-comparer'." + :type '(repeat + (cons + (choice :tag "Sort order" string symbol) + (choice + (const :tag "None (do not sort)" nil) + (function :tag "Sorting Predicate") + (list :tag "Sorting Multi-Predicate" + (repeat (function :tag "Component Predicate")) + (choice + (const :tag "None" nil) + (function :tag "Final Predicate")))))) + :group 'bookmark-plus)) + +(defcustom bmkp-propertize-bookmark-names-flag (> emacs-major-version 20) + "*Non-nil means to propertize bookmark names to hold full bookmark data. +This means that you can effectively have more than one bookmark with +the same name. + +Emacs 20 users: If you need to use your bookmarks with Emacs 20 then +set this to nil. In particular, if your bookmark file was written +with this as non-nil, then it contains propertized strings which are +unreadable by Emacs 20. To convert the file to be usable with Emacs +20 you must, in Emacs 21 or later, set this to nil and then do `M-x +bookmark-save'." + :type 'boolean :group 'bookmark-plus) + +;;(@* "Internal Variables") +;;; Internal Variables ----------------------------------------------- + +(defconst bmkp-bmenu-header-lines 5 + "Number of lines used for the `*Bookmark List*' header.") + +(defconst bmkp-bmenu-marks-width 4 + "Number of columns (chars) used for the `*Bookmark List*' marks columns. +Bookmark names thus begin in this column number (since zero-based).") + + +(defvar bmkp-bmenu-before-hide-marked-alist () + "Copy of `bookmark-alist' made before hiding marked bookmarks.") + +(defvar bmkp-bmenu-before-hide-unmarked-alist () + "Copy of `bookmark-alist' made before hiding unmarked bookmarks.") + +(defvar bmkp-bmenu-define-command-history () + "History of names of commands you have defined for `*Bookmark List*'.") + +(defvar bmkp-bmenu-filter-function nil "Latest filtering function for `*Bookmark List*' display.") + +(defvar bmkp-bmenu-filter-pattern "" "Regexp for incremental filtering.") + +(defvar bmkp-bmenu-filter-timer nil "Timer used for incremental filtering.") + +(defvar bmkp-bmenu-first-time-p t + "Non-nil means bookmark list has not yet been shown after quitting it. +Quitting the list or the Emacs session resets this to t. +The first time the list is displayed, it is set to nil.") + +(defvar bmkp-bmenu-marked-bookmarks () + "Names of the marked bookmarks. +This includes possibly omitted bookmarks, that is, bookmarks listed in +`bmkp-bmenu-omitted-bookmarks'.") + +(defvar bmkp-bmenu-title "" "Latest title for `*Bookmark List*' display.") + +(defvar bmkp-flagged-bookmarks () + "Alist of bookmarks that are flagged for deletion in `*Bookmark List*'.") + +;; This is a general variable. It is in this file because it is used only in the bmenu code. +(defvar bmkp-last-bmenu-bookmark nil "The name of the last bookmark current in the bookmark list.") + +;;(@* "Compatibility Code for Older Emacs Versions") +;;; Compatibility Code for Older Emacs Versions ---------------------- + +(when (or (< emacs-major-version 23) (and (= emacs-major-version 23) (= emacs-minor-version 1))) + (defmacro with-buffer-modified-unmodified (&rest body) + "Save and restore `buffer-modified-p' state around BODY." + (let ((was-modified (make-symbol "was-modified"))) + `(let ((,was-modified (buffer-modified-p))) + (unwind-protect (progn ,@body) + (set-buffer-modified-p ,was-modified)))))) + +(when (< emacs-major-version 22) + (defun bookmark-bmenu-relocate () + "Change the file path of the bookmark on the current line, +prompting with completion for the new path." + (interactive) + (let ((bmk (bookmark-bmenu-bookmark)) + (thispoint (point))) + (when bmk (bookmark-relocate bmk)) + (goto-char thispoint)))) + +;;(@* "Menu List Replacements (`bookmark-bmenu-*')") +;;; Menu List Replacements (`bookmark-bmenu-*') ---------------------- + + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Return t. Value doesn't mean anything (didn't anyway), but must be non-nil for vanilla Emacs. +;; 2. Do not count lines. Just make sure we're on a bookmark line. +;; +(defalias 'bookmark-bmenu-check-position 'bookmark-bmenu-ensure-position) +(defun bookmark-bmenu-ensure-position () + "Move to the beginning of the nearest bookmark line." + (beginning-of-line) + (unless (bookmark-bmenu-bookmark) + (if (and (bolp) (eobp)) + (beginning-of-line 0) + (goto-char (point-min)) + (forward-line bmkp-bmenu-header-lines))) + t) ; Older vanilla bookmark code depends on non-nil value. + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Add bookmark to `bmkp-bmenu-marked-bookmarks'. Delete it from `bmkp-flagged-bookmarks'. +;; 2. Don't call `bookmark-bmenu-ensure-position' again at end. +;; 3. Raise error if not in `*Bookmark List*'. +;; 4. Narrower scope for `with-buffer-modified-unmodified' and `let'. +;; 5. If current sort is `s >' (marked first or last), and it was unmarked before, then re-sort. +;; 6. Added optional arg NO-RE-SORT-P to inhibit #5. +;; 7. Added optional arg MSG-P. +;; 8. Call `bmkp-bmenu-mode-line'. +;; +;;;###autoload (autoload 'bookmark-bmenu-mark "bookmark+") +(defun bookmark-bmenu-mark (&optional no-re-sort-p msg-p) ; Bound to `m' in bookmark list + "Mark the bookmark on this line, using mark `>'. +Add its name to `bmkp-bmenu-marked-bookmarks', after propertizing it +with the full bookmark as `bmkp-full-record'. + +If the bookmark was unmarked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive (list nil 'MSG-P)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (beginning-of-line) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (delete-char 1) (insert ?>) (put-text-property (1- (point)) (point) 'face 'bmkp->-mark))) + (let* ((bname (bookmark-bmenu-bookmark)) + (bmk (bmkp-bookmark-record-from-name bname)) + (was-unmarked-p nil)) + ;; Put full bookmark on BNAME as property `bmkp-full-record'. + (put-text-property 0 (length bname) 'bmkp-full-record bmk bname) + ;; This is the same as `add-to-list' with `eq' (not available for Emacs 20-21). + (unless (memq bname bmkp-bmenu-marked-bookmarks) + (setq bmkp-bmenu-marked-bookmarks (cons bname bmkp-bmenu-marked-bookmarks) + was-unmarked-p t)) + (setq bmkp-flagged-bookmarks (delq bmk bmkp-flagged-bookmarks)) + (unless no-re-sort-p + ;; If it was unmarked but now is marked, and if sort order is `s >', then re-sort. + (when (and was-unmarked-p (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list (not msg-p)) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk)))))) + (forward-line 1) + (when (fboundp 'bmkp-bmenu-mode-line) (bmkp-bmenu-mode-line))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Remove bookmark from `bmkp-bmenu-marked-bookmarks' and `bmkp-flagged-bookmarks'. +;; 2. Use `bmkp-delete-bookmark-name-from-list', not `delete'. +;; 3. Don't call `bookmark-bmenu-ensure-position' again at end. +;; 4. Raise error if not in `*Bookmark List*'. +;; 5. Narrower scope for `with-buffer-modified-unmodified' and `let'. +;; 6. If current sort is `s >' (marked first or last), and it was marked before, then re-sort. +;; 7. Added optional arg NO-RE-SORT-P to inhibit #6. +;; 8. Added optional arg MSG-P. +;; 9. Call `bmkp-bmenu-mode-line'. +;; +;;;###autoload (autoload 'bookmark-bmenu-unmark "bookmark+") +(defun bookmark-bmenu-unmark (&optional backup no-re-sort-p msg-p) ; Bound to `u' in bookmark list + "Unmark the bookmark on this line, then move down to the next. +With a prefix argument, move up instead. + +If the bookmark was marked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil optional arg BACKUP (prefix arg) means move up. +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive (list current-prefix-arg nil 'MSG-P)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (beginning-of-line) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (delete-char 1) (insert " "))) + (let ((was-marked-p (memq (bookmark-bmenu-bookmark) bmkp-bmenu-marked-bookmarks))) + (setq bmkp-bmenu-marked-bookmarks (bmkp-delete-bookmark-name-from-list + (bookmark-bmenu-bookmark) bmkp-bmenu-marked-bookmarks) + bmkp-flagged-bookmarks (delq (bmkp-bookmark-record-from-name (bookmark-bmenu-bookmark)) + bmkp-flagged-bookmarks)) + (unless no-re-sort-p + ;; If it was marked but now is unmarked, and if sort order is `s >', then re-sort. + (when (and was-marked-p (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list (not msg-p)) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk)))))) + (forward-line (if backup -1 1)) + (when (fboundp 'bmkp-bmenu-mode-line) (bmkp-bmenu-mode-line))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Do not use `bookmark-bmenu-ensure-position' as a test - it always returns non-nil anyway. +;; And don't call it again the end. +;; 2. Use `bmkp-delete-bookmark-name-from-list', not `delete'. +;; 3. Use face `bmkp-D-mark' on the `D' flag. +;; 4. Raise error if not in buffer `*Bookmark List*'. +;; 5. Remove bookmark from `bmkp-bmenu-marked-bookmarks'. Add it to `bmkp-flagged-bookmarks'. +;; 6. Call `bmkp-bmenu-mode-line'. +;; +;;;###autoload (autoload 'bmkp-bmenu-flag-for-deletion "bookmark+") +(defalias 'bmkp-bmenu-flag-for-deletion 'bookmark-bmenu-delete) ; A better name. +;;;###autoload (autoload 'bookmark-bmenu-delete "bookmark+") +(defun bookmark-bmenu-delete () ; Bound to `d', `k' in bookmark list + "Flag this bookmark for deletion, using mark `D'. +Use `\\\\[bookmark-bmenu-execute-deletions]' to carry out \ +the deletions." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (beginning-of-line) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (delete-char 1) (insert ?D) (put-text-property (1- (point)) (point) 'face 'bmkp-D-mark))) + (when (bookmark-bmenu-bookmark) ; Should never be nil, but just to be safe. + (setq bmkp-bmenu-marked-bookmarks (bmkp-delete-bookmark-name-from-list + (bookmark-bmenu-bookmark) bmkp-bmenu-marked-bookmarks)) + ;; This is the same as `add-to-list' with `eq' (not available for Emacs 20-21). + (let ((bmk (bmkp-bookmark-record-from-name (bookmark-bmenu-bookmark)))) + (unless (memq bmk bmkp-flagged-bookmarks) + (setq bmkp-flagged-bookmarks (cons bmk bmkp-flagged-bookmarks))))) + (forward-line 1) + (when (fboundp 'bmkp-bmenu-mode-line) (bmkp-bmenu-mode-line))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Do not move forward another line at end. Leave point above flagged bookmark. +;; +;;;###autoload (autoload 'bmkp-bmenu-flag-for-deletion-backwards "bookmark+") +(defalias 'bmkp-bmenu-flag-for-deletion-backwards 'bookmark-bmenu-delete-backwards) ; A better name. +;;;###autoload (autoload 'bookmark-bmenu-delete-backwards "bookmark+") +(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-bmenu-delete) + (forward-line -2) + (bookmark-bmenu-ensure-position)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg NO-MSG-P. +;; 2. Rebuild the menu list using the last filtered alist in use, `bmkp-latest-bookmark-alist'. +;; 3. Update the menu-list title. +;; +(defun bookmark-bmenu-surreptitiously-rebuild-list (&optional no-msg-p) + "Rebuild the bookmark list, if it exists. +Non-nil optional arg NO-MSG-P means do not show progress messages." + (when (get-buffer bmkp-bmenu-buffer) + (unless no-msg-p (message "Updating bookmark-list display...")) + (save-excursion (save-window-excursion (let ((bookmark-alist bmkp-latest-bookmark-alist)) + (bookmark-bmenu-list 'filteredp)))) + (unless no-msg-p (message "Updating bookmark-list display...done")))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added arg FILTEREDP. +;; 2. Handles also region bookmarks and buffer (non-file) bookmarks. +;; 3. Uses `pop-to-buffer', not `switch-to-buffer', so we respect `special-display-*' +;; (but keep `one-window-p' if that's the case). +;; 4. If option `bmkp-bmenu-state-file' is non-nil, then the first time since the last quit +;; (or the last Emacs session) restores the last menu-list state. +;; 5. If option `bmkp-bmenu-commands-file' is non-nil, then read that file, which contains +;; user-defined `*Bookmark List*' commands. +;; 6. Many differences in the display itself - see the doc. +;; +;;;###autoload (autoload 'list-bookmarks "bookmark+") +(defalias 'list-bookmarks 'bookmark-bmenu-list) +;;;###autoload (autoload 'bookmark-bmenu-list "bookmark+") +(defun bookmark-bmenu-list (&optional filteredp msg-p) ; Bound to `C-x x e', `C-x r l' + "Display a list of existing bookmarks, in buffer `*Bookmark List*'. +The leftmost column of a bookmark entry shows `D' if the bookmark is + flagged for deletion, or `>' if it is marked normally. +The second column shows `t' if the bookmark has tags. +The third column shows `a' if the bookmark has an annotation. + +The following faces are used for the list entries. +Use `customize-face' if you want to change the appearance. + + `bmkp-bad-bookmark', `bmkp-bookmark-file', `bmkp-bookmark-list', + `bmkp-buffer', `bmkp-desktop', `bmkp-file-handler', `bmkp-function', + `bmkp-gnus', `bmkp-info', `bmkp-local-directory', + `bmkp-local-file-without-region', `bmkp-local-file-with-region', + `bmkp-man', `bmkp-no-jump', `bmkp-no-local', `bmkp-non-file', + `bmkp-remote-file', `bmkp-sequence', `bmkp-snippet', + `bmkp-su-or-sudo', `bmkp-url', `bmkp-variable-list' + +If option `bmkp-bmenu-state-file' is non-nil then the state of the +displayed bookmark-list is saved when you quit it, and it is restored +when you next use this command. That saved state is not restored, +however, if it represents a different file from the current bookmark +file. + +If you call this interactively when buffer `*Bookmark List*' exists, +that buffer is refreshed to show all current bookmarks, and any +markings are removed. If you instead want to show the buffer in its +latest state then just do that: use `C-x b' or similar. If you want +to refresh the displayed buffer, to show the latest state, reflecting +any additions, deletions, renamings, and so on, use \\\ +`\\[bmkp-bmenu-refresh-menu-list]'. + + +Non-interactively: + + - Non-nil optional argument FILTEREDP means the bookmark list has + been filtered, which means: + + * Use `bmkp-bmenu-title' not the default menu-list title. + * Do not reset `bmkp-latest-bookmark-alist' to `bookmark-alist'. + + - Non-nil optional arg MSG-P means display progress messages." + (interactive "i\np") + (bookmark-maybe-load-default-file) + (when msg-p (message "Gathering bookmarks to display...")) + (when (and bmkp-bmenu-first-time-p bmkp-bmenu-commands-file + (file-readable-p bmkp-bmenu-commands-file)) + (when (file-directory-p bmkp-bmenu-commands-file) + (error "`%s' is a directory, not a file" bmkp-bmenu-commands-file)) + (with-current-buffer (let ((enable-local-variables ()) + (emacs-lisp-mode-hook nil)) + (find-file-noselect bmkp-bmenu-commands-file)) + (goto-char (point-min)) + (while (not (eobp)) (condition-case nil (eval (read (current-buffer))) (error nil))) + (kill-buffer (current-buffer)))) + (cond ((and bmkp-bmenu-first-time-p bmkp-bmenu-state-file ; Restore from state file. + (file-readable-p bmkp-bmenu-state-file)) + (when (file-directory-p bmkp-bmenu-state-file) + (error "`%s' is a directory, not a file" bmkp-bmenu-state-file)) + (let ((state ())) + (with-current-buffer (let ((enable-local-variables nil) + (emacs-lisp-mode-hook nil)) + (find-file-noselect bmkp-bmenu-state-file)) + (goto-char (point-min)) + (setq state (condition-case nil (read (current-buffer)) (error nil))) + (kill-buffer (current-buffer))) + (let ((last-bookmark-file-from-state (cdr (assq 'last-bookmark-file state)))) + (when (and (consp state) + ;; If bookmark file has changed, then do not use state saved from other file. + (or (not last-bookmark-file-from-state) + (bmkp-same-file-p last-bookmark-file-from-state + bmkp-current-bookmark-file))) + (setq bmkp-sort-comparer (cdr (assq 'last-sort-comparer state)) + bmkp-reverse-sort-p (cdr (assq 'last-reverse-sort-p state)) + bmkp-reverse-multi-sort-p (cdr (assq 'last-reverse-multi-sort-p state)) + bmkp-latest-bookmark-alist (cdr (assq 'last-latest-bookmark-alist state)) + bmkp-bmenu-omitted-bookmarks (cdr (assq 'last-bmenu-omitted-bookmarks state)) + bmkp-bmenu-marked-bookmarks (cdr (assq 'last-bmenu-marked-bookmarks state)) + bmkp-bmenu-filter-function (cdr (assq 'last-bmenu-filter-function state)) + bmkp-bmenu-filter-pattern (or (cdr (assq 'last-bmenu-filter-pattern state)) + "") + bmkp-bmenu-title (cdr (assq 'last-bmenu-title state)) + bmkp-last-bmenu-bookmark (cdr (assq 'last-bmenu-bookmark state)) + bmkp-last-specific-buffer (cdr (assq 'last-specific-buffer state)) + bmkp-last-specific-file (cdr (assq 'last-specific-file state)) + bookmark-bmenu-toggle-filenames (cdr (assq 'last-bmenu-toggle-filenames state)) + bmkp-last-bookmark-file (or (cdr (assq 'last-previous-bookmark-file state)) + bmkp-current-bookmark-file) + bmkp-current-bookmark-file last-bookmark-file-from-state + bmkp-bmenu-before-hide-marked-alist + (cdr (assq 'last-bmenu-before-hide-marked-alist state)) + bmkp-bmenu-before-hide-unmarked-alist + (cdr (assq 'last-bmenu-before-hide-unmarked-alist state)))))) + (setq bmkp-bmenu-first-time-p nil) + (let ((bookmark-alist (bmkp-refresh-latest-bookmark-list))) ; This sets *-latest-* also. + (bmkp-bmenu-list-1 'filteredp nil msg-p)) + ;; Propertize bookmark names if not already propertized (lists saved with Emacs 20 or + ;; not `bmkp-propertize-bookmark-names-flag'). Check only the first, to guess propertized. + (when (and (consp bmkp-bmenu-marked-bookmarks) + (not (get-text-property 0 'bmkp-full-record (car bmkp-bmenu-marked-bookmarks)))) + (setq bmkp-bmenu-marked-bookmarks + (condition-case nil + (mapcar (lambda (bname) + (if (get-text-property 0 'bmkp-full-record bname) + bname + (put-text-property 0 (length bname) 'bmkp-full-record + (bmkp-bookmark-record-from-name bname) bname) + bname)) + bmkp-bmenu-marked-bookmarks) + (error ())))) ; Reset to () if any name is not a current bookmark. + (when (and (consp bmkp-bmenu-omitted-bookmarks) + (not (get-text-property 0 'bmkp-full-record (car bmkp-bmenu-omitted-bookmarks)))) + (setq bmkp-bmenu-omitted-bookmarks + (condition-case nil + (mapcar (lambda (bname) + (if (get-text-property 0 'bmkp-full-record bname) + bname + (put-text-property 0 (length bname) 'bmkp-full-record + (bmkp-bookmark-record-from-name bname) bname) + bname)) + bmkp-bmenu-omitted-bookmarks) + (error ())))) ; Reset to () if any name is not a current bookmark. + (when bmkp-last-bmenu-bookmark + (with-current-buffer (get-buffer bmkp-bmenu-buffer) + (bmkp-bmenu-goto-bookmark-named bmkp-last-bmenu-bookmark)))) + (t + (setq bmkp-bmenu-first-time-p nil) + (bmkp-bmenu-list-1 filteredp (or msg-p (not (get-buffer bmkp-bmenu-buffer))) msg-p)))) + +(defun bmkp-bmenu-list-1 (filteredp reset-p interactivep) + "Helper for `bookmark-bmenu-list'. +See `bookmark-bmenu-list' for the description of FILTEREDP. +Reset `bmkp-modified-bookmarks' and `bmkp-flagged-bookmarks'. +Non-nil RESET-P means reset `bmkp-bmenu-marked-bookmarks' also. +Non-nil INTERACTIVEP means `bookmark-bmenu-list' was called + interactively, so pop to bookmark list and communicate sort order." + (setq bmkp-modified-bookmarks () + bmkp-flagged-bookmarks ()) + (when reset-p (setq bmkp-bmenu-marked-bookmarks ())) +;; $$$$$$ Took out 2015/01/22. (unless filteredp (setq bmkp-latest-bookmark-alist bookmark-alist)) + (if interactivep + (let ((one-win-p (one-window-p))) + (pop-to-buffer (get-buffer-create bmkp-bmenu-buffer)) + (when one-win-p (delete-other-windows))) + (set-buffer (get-buffer-create bmkp-bmenu-buffer))) + (let* ((inhibit-read-only t) + (title (if (and filteredp bmkp-bmenu-title (not (equal "" bmkp-bmenu-title))) + bmkp-bmenu-title + "All Bookmarks")) + (show-image-file-icon-p (and (fboundp 'display-images-p) (display-images-p) + bmkp-bmenu-image-bookmark-icon-file + (file-readable-p bmkp-bmenu-image-bookmark-icon-file)))) + (erase-buffer) + (when (fboundp 'remove-images) (remove-images (point-min) (point-max))) + (insert (format "%s\n%s\n" title (make-string (length title) ?-))) + (add-text-properties (point-min) (point) (bmkp-face-prop 'bmkp-heading)) + (goto-char (point-min)) + (insert (format "Bookmark file:\n%s\n\n" bmkp-current-bookmark-file)) + (forward-line bmkp-bmenu-header-lines) + (let ((max-width 0) + name markedp flaggedp tags annotation temporaryp start) + (setq bmkp-sorted-alist (bmkp-sort-omit bookmark-alist + (and (not (eq bmkp-bmenu-filter-function + 'bmkp-omitted-alist-only)) + bmkp-bmenu-omitted-bookmarks))) + (dolist (bmk bmkp-sorted-alist) + (setq max-width (max max-width (string-width (bmkp-bookmark-name-from-record bmk))))) + (setq max-width (+ max-width bmkp-bmenu-marks-width)) + (dolist (bmk bmkp-sorted-alist) + (setq name (bmkp-bookmark-name-from-record bmk) + markedp (bmkp-marked-bookmark-p bmk) + flaggedp (bmkp-flagged-bookmark-p bmk) + tags (bmkp-get-tags bmk) + annotation (bookmark-get-annotation bmk) + start (+ bmkp-bmenu-marks-width (point))) + (cond (flaggedp (insert "D") (put-text-property (1- (point)) (point) 'face 'bmkp-D-mark)) + (markedp (insert ">") (put-text-property (1- (point)) (point) 'face 'bmkp->-mark)) + (t (insert " "))) + (if (null tags) + (insert " ") + (insert "t") (put-text-property (1- (point)) (point) 'face 'bmkp-t-mark)) + (cond ((bmkp-temporary-bookmark-p bmk) + (insert "X") (put-text-property (1- (point)) (point) 'face 'bmkp-X-mark)) + ((and annotation (not (string-equal annotation ""))) + (insert "a") (put-text-property (1- (point)) (point) 'face 'bmkp-a-mark)) + (t (insert " "))) + (if (not (memq bmk bmkp-modified-bookmarks)) + (insert " ") + (insert "*") + (put-text-property (1- (point)) (point) 'face 'bmkp-*-mark)) + (when (and (featurep 'bookmark+-lit) (bmkp-get-lighting bmk)) ; Highlight highlight overrides. + (put-text-property (1- (point)) (point) 'face 'bmkp-light-mark)) + (when (and (bmkp-image-bookmark-p bmk) show-image-file-icon-p) + (let ((image (create-image bmkp-bmenu-image-bookmark-icon-file nil nil :ascent 95))) + (when image (put-image image (point))))) + (insert name) + (move-to-column max-width t) + (bmkp-bmenu-propertize-item bmk start (point)) + (insert "\n"))) + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (bookmark-bmenu-mode) + (when (and bookmark-alist bookmark-bmenu-toggle-filenames) + (bookmark-bmenu-toggle-filenames t 'NO-MSG-P)) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window))) + (when (fboundp 'bmkp-bmenu-mode-line) (bmkp-bmenu-mode-line)) + (when (and interactivep bmkp-sort-comparer) (bmkp-msg-about-sort-order (bmkp-current-sort-order)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; Redefined. +;; 1. Get name of the current bookmark from text property `bmkp-bookmark-name'. +;; 2. Added optional arg FULL, to return full bookmark record. +;; 3. Use `condition-case' in case we're at eob (so cannot advance). +;; +(defun bookmark-bmenu-bookmark (&optional full) + "Return the name of the bookmark on this line. +Normally, the string returned is propertized with property +`bmkp-full-record', which records the full bookmark record. +Return nil if no bookmark on this line. +Non-nil optional FULL means return the bookmark record, not the name." + (condition-case nil + (let ((name (save-excursion (forward-line 0) (forward-char bmkp-bmenu-marks-width) + (get-text-property (point) 'bmkp-bookmark-name)))) + (if full (get-text-property 0 'bmkp-full-record name) name)) + (error nil))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Mode-line major-mode name is different, and indicates whether in temporary bookmarking minor mode. +;; 2. Doc string is different. +;; +(defun bookmark-bmenu-mode () + "Major mode for editing a list of bookmarks. + +Each line represents an Emacs bookmark. Keys without prefix `C-x' are +available only here (in `*Bookmark List*'). Other keys are available +everywhere. + +Remember that you can see all bindings for a prefix key by hitting it, +then `C-h'. E.g., `s C-h' to see keys with prefix `s' (sorting keys). + +More bookmarking help below. + + +Help - Bookmark Info +-------------------- + +\\\ +\\[bookmark-bmenu-toggle-filenames]\t- Toggle showing filenames next to bookmarks +\\[bmkp-bmenu-describe-this-bookmark]\t- Show information about bookmark (`C-u': internal form) +\\[bmkp-bmenu-describe-this+move-down]\t- Show the info, then move to next bookmark +\\[bmkp-bmenu-describe-this+move-up]\t- Show the info, then move to previous bookmark +\\[bmkp-bmenu-describe-marked]\t- Show info about the marked bookmarks (`C-u': internal form) +\\[bookmark-bmenu-locate]\t- Show location of bookmark (in minibuffer) +\\[bookmark-bmenu-show-annotation]\t- Show bookmark's annotation +\\[bookmark-bmenu-show-all-annotations]\t- Show the annotations of all annotated bookmarks + +\\[bmkp-list-defuns-in-commands-file] +\t- List the commands defined in `bmkp-bmenu-commands-file' + + +Bookmark-List Display (`*Bookmark List*') +----------------------------------------- + +\\[bmkp-toggle-saving-menu-list-state]\t- Toggle autosaving bookmark-list display state +\\[bmkp-save-menu-list-state]\t- Save bookmark-list display state + +\\[bmkp-bmenu-refresh-menu-list]\t- Refresh display to current bookmark list (`C-u': from file) +\\[bmkp-bmenu-show-all]\t- Show all bookmarks +\\[bmkp-toggle-bookmark-set-refreshes] +\t- Toggle whether `bookmark-set' refreshes the bookmark list +\\[bmkp-bmenu-mode-status-help]\t- Show this help +\\[bmkp-bmenu-quit]\t- Quit (`*Bookmark List*') + + +Bookmark Files +-------------- + +\\[bmkp-toggle-saving-bookmark-file]\t- Toggle autosaving to the current bookmark file +\\[bookmark-bmenu-save]\t- Save bookmarks now (`C-u': Save As... - prompt for file) +\\[bmkp-empty-file]\t- Empty existing bookmark file or create new, empty one + +C-u \\[bmkp-bmenu-refresh-menu-list]\t- Revert to bookmarks in the bookmark file (overwrite load) +\\[bmkp-switch-bookmark-file-create]\t- Switch to a different bookmark file (overwrite load) +C-u \\[bmkp-switch-bookmark-file-create]\t- Switch back to the previous bookmark file (overwrite load) +\\[bookmark-bmenu-load]\t- Add bookmarks from a different bookmark file (extra load) +\\[bmkp-bmenu-load-marked-bookmark-file-bookmarks]\t- Load marked bookmark-file bookmarks \ +\(extra load) + +\\[bmkp-bmenu-move-marked-to-bookmark-file]\t- Move the marked bookmarks to a bookmark file +\\[bmkp-bmenu-copy-marked-to-bookmark-file]\t- Copy the marked bookmarks to a bookmark file +\\[bmkp-bmenu-create-bookmark-file-from-marked]\t- Copy the marked bookmarks to a new bookmark file +C-u \\[bmkp-bmenu-create-bookmark-file-from-marked]\t- Same, plus create bookmark-file bookmark for it + + +General +------- + +Here: + +\\[bmkp-bmenu-dired-marked]\t- Open Dired for the marked file and directory bookmarks +\\[bmkp-bmenu-make-sequence-from-marked] +\t- Create a sequence bookmark from the marked bookmarks +\\[bmkp-temporary-bookmarking-mode]\t- Toggle temporary-only bookmarking (new, empty bookmark file) + +Anywhere: + +\\\ +\\[bmkp-toggle-autotemp-on-set]\t- Toggle making bookmarks temporary when setting them +\\[bmkp-set-bookmark-file-bookmark]\t- Create a bookmark to a bookmark file (`j y' to load it) +\\[bmkp-delete-bookmarks]\t- Delete some bookmarks at point or all in buffer +\\[bmkp-make-function-bookmark]\t- Create a function bookmark + +\\[bmkp-choose-navlist-of-type]\t- Set the navlist to the bookmarks of a type you choose +\\[bmkp-choose-navlist-from-bookmark-list]\t- Set the navlist to the bookmarks of a \ +bookmark-list bookmark +\\[bmkp-navlist-bmenu-list]\t- Open `*Bookmark List*' for bookmarks in navlist + +\\[bmkp-this-file/buffer-bmenu-list]\t- Open `*Bookmark List*' for bookmarks in current file/buffer +\\[bmkp-switch-to-bookmark-file-this-file/buffer]\t- Switch to bookmark file for current file/buffer +\\[bmkp-save-bookmarks-this-file/buffer]\t- Save bookmarks for current file/buffer to a file +\\ + + +Create/Set Bookmarks (anywhere) +-------------------- + +\\[bmkp-toggle-autonamed-bookmark-set/delete]\t- Set/delete an autonamed bookmark here +\\[bmkp-autofile-set]\t- Set and autoname a bookmark for a file +\\[bmkp-file-target-set]\t- Set a bookmark for a file +\\[bmkp-url-target-set]\t- Set a bookmark for a URL +\\[bmkp-bookmark-set-confirm-overwrite]\t\t- Set a bookmark here +\\[bmkp-set-desktop-bookmark]\t\t- Set a bookmark for the current desktop +\\[bmkp-set-bookmark-file-bookmark]\t\t- Set a bookmark for a bookmark file +\\[bmkp-set-snippet-bookmark]\t- Save the region text as a snippet bookmark + + +Jump to (Visit) Bookmarks +------------------------- + +\\[bookmark-bmenu-this-window]\t- This bookmark in the same window +\\[bookmark-bmenu-other-window]\t- This bookmark in another window +\\[bookmark-bmenu-switch-other-window]\t- This bookmark in other window, without selecting it +\\[bookmark-bmenu-2-window]\t- This bookmark and last-visited bookmark +\\[bookmark-bmenu-1-window]\t- This bookmark in a full-frame window +\\[bookmark-bmenu-other-frame]\t- This bookmark in another frame + +\\[bmkp-bmenu-jump-to-marked]\t- Bookmarks marked `>', in other windows + +Prefix `j' uses another window; prefix `J' reuses this window: + +\\[bookmark-jump-other-window]\t- Bookmark by name +\\[bmkp-jump-in-navlist-other-window]\t- Bookmark in the navigation list +\\[bmkp-lighted-jump-other-window]\t- Highlighted bookmark + +\\[bmkp-jump-to-type-other-window]\t- Bookmark by type +\\[bmkp-autonamed-jump-other-window]\t- Autonamed bookmark +\\[bmkp-autonamed-this-buffer-jump-other-window]\t- Autonamed bookmark in this buffer +\\[bmkp-temporary-jump-other-window]\t- Temporary bookmark + +\\[bmkp-autofile-jump-other-window]\t- Autofile bookmark +\\[bmkp-dired-jump-other-window]\t- Dired bookmark +\\[bmkp-file-jump-other-window]\t- File or directory bookmark +\\[bmkp-dired-this-dir-jump-other-window]\t- Dired bookmark for this dir +\\[bmkp-file-this-dir-jump-other-window]\t- Bookmark for a file or subdir in this dir +\\[bmkp-local-file-jump-other-window]\t- Local-file bookmark +\\[bmkp-remote-file-jump-other-window]\t- Remote-file bookmark +\\[bmkp-non-file-jump-other-window]\t- Non-file (buffer) bookmark + +\\[bmkp-desktop-jump]\t- Desktop bookmark +\\[bmkp-bookmark-list-jump]\t- Bookmark-list bookmark +\\[bmkp-bookmark-file-jump]\t- Bookmark-file bookmark + +\\[bmkp-region-jump-other-window]\t- Region bookmark (restore region) +\\[bmkp-snippet-to-kill-ring]\t- Snippet bookmark (copy to `kill-ring') +\\[bmkp-image-jump-other-window]\t- Image-file bookmark +\\[bmkp-info-jump-other-window]\t- Info bookmark +\\[bmkp-man-jump-other-window]\t- `man'-page bookmark +\\[bmkp-gnus-jump-other-window]\t- Gnus bookmark +\\[bmkp-url-jump-other-window]\t- URL bookmark +\\[bmkp-variable-list-jump]\t- Variable-list bookmark + +\\[bmkp-some-tags-jump-other-window]\t- Bookmark having some tags you specify +\\[bmkp-all-tags-jump-other-window]\t- Bookmark having each tag you specify +\\[bmkp-some-tags-regexp-jump-other-window]\t- Bookmark having a tag that matches a regexp +\\[bmkp-all-tags-regexp-jump-other-window]\t- Bookmark having all its tags match a regexp +\\[bmkp-file-some-tags-jump-other-window]\t- File bookmark having some tags you specify +\\[bmkp-file-all-tags-jump-other-window]\t- File bookmark having each tag you specify +\\[bmkp-file-some-tags-regexp-jump-other-window]\t- File bookmark having a tag that matches a regexp +\\[bmkp-file-all-tags-regexp-jump-other-window]\t- File bookmark having all its tags match a regexp +\\[bmkp-file-this-dir-some-tags-jump-other-window]\t- File in this dir having some tags you specify +\\[bmkp-file-this-dir-all-tags-jump-other-window]\t- File in this dir having each tag you specify +\\[bmkp-file-this-dir-some-tags-regexp-jump-other-window]\t- \ +File in this dir having a tag that matches a regexp +\\[bmkp-file-this-dir-all-tags-regexp-jump-other-window]\t- \ +File in this dir having all its tags match a regexp + + +Autonamed Bookmarks +------------------- + +\\[bmkp-toggle-autonamed-bookmark-set/delete]\t- Create/delete autonamed bookmark at point +C-u \\[bmkp-toggle-autonamed-bookmark-set/delete]\t- Delete all autonamed bookmarks in current buffer +\\[bmkp-autonamed-jump-other-window]\t\t- Jump to an autonamed bookmark +\\[bmkp-autonamed-this-buffer-jump-other-window]\t\t- Jump to an autonamed bookmark in a given buffer + + +Cycle Bookmarks (anywhere) +--------------- + +\\[bmkp-next-bookmark-this-file/buffer-repeat]...\t- Next bookmark in buffer (C-x x n, C-x x C-n) +\\[bmkp-previous-bookmark-this-file/buffer-repeat]...\t- Prev bookmark in buffer (C-x x p, \ +C-x x C-p) +\\[bmkp-next-bookmark-repeat]...- Next bookmark in navlist (C-x x f, C-x x C-f) +\\[bmkp-previous-bookmark-repeat]...\t- Prev bookmark in navlist (C-x x b, C-x x C-b) +\\[bmkp-next-bookmark-w32-repeat]...\t- MS Windows `Open' next in navlist (C-x x next) +\\[bmkp-previous-bookmark-w32-repeat]...- MS Windows `Open' previous in navlist (C-x x prior) +\\[bmkp-next-lighted-this-buffer-repeat]...- Next highlighted bookmark in buffer (C-x x C-down) +\\[bmkp-previous-lighted-this-buffer-repeat]...\t- Prev highlighted bookmark in buffer (C-x x C-up) + + Similar, but not bound to keys by default: + \\[bmkp-next-autonamed-bookmark-repeat] (and `previous') + \\[bmkp-next-bookmark-list-bookmark-repeat] (and `previous') + \\[bmkp-next-desktop-bookmark-repeat] (and `previous') + \\[bmkp-next-dired-bookmark-repeat] (and `previous') + \\[bmkp-next-eww-bookmark-repeat] (and `previous') + \\[bmkp-next-file-bookmark-repeat] (and `previous') + \\[bmkp-next-gnus-bookmark-repeat] (and `previous') + \\[bmkp-next-info-bookmark-repeat] (and `previous') + \\[bmkp-next-lighted-bookmark-repeat] (and `previous') + \\[bmkp-next-local-file-bookmark-repeat] (and `previous') + \\[bmkp-next-man-bookmark-repeat] (and `previous') + \\[bmkp-next-non-file-bookmark-repeat] (and `previous') + \\[bmkp-next-remote-file-bookmark-repeat] (and `previous') + \\[bmkp-next-specific-buffers-bookmark-repeat] (and `previous') + \\[bmkp-next-specific-files-bookmark-repeat] (and `previous') + \\[bmkp-next-url-bookmark-repeat] (and `previous') + \\[bmkp-next-variable-list-bookmark-repeat] (and `previous') + + +Search-and-Replace in Bookmark Targets (here, in sort order) +-------------------------------------- + +\\[bmkp-bmenu-isearch-marked-bookmarks]\t- Isearch the marked bookmarks (`C-u': all) +\\[bmkp-bmenu-isearch-marked-bookmarks-regexp]\t- Regexp-isearch the marked bookmarks (`C-u': all) +\\[bmkp-bmenu-search-marked-bookmarks-regexp]\t- Regexp-search the marked file bookmarks (`C-u': all) +\\[bmkp-bmenu-query-replace-marked-bookmarks-regexp]\t\t- Query-replace the marked file bookmarks + + +Mark/Unmark Bookmarks +--------------------- + +\(Mark means `>'. Flag means `D'. See also `Tags', below.) + +\\[bmkp-bmenu-flag-for-deletion]\t- Flag bookmark `D' for deletion, then move down +\\[bmkp-bmenu-flag-for-deletion-backwards]\t- Flag bookmark `D' for deletion, then move up + +\\[bookmark-bmenu-mark]\t- Mark bookmark +\\[bookmark-bmenu-unmark]\t- Unmark bookmark (`C-u': move up one line) +\\[bookmark-bmenu-backup-unmark]\t- Unmark previous bookmark (move up, then unmark) + +\\[bmkp-bmenu-mark-all]\t- Mark all bookmarks +\\[bmkp-bmenu-regexp-mark]\t- Mark all bookmarks whose names match a regexp +\\[bmkp-bmenu-unmark-all]\t- Unmark all bookmarks (`C-u': interactive query) +\\[bmkp-bmenu-toggle-marks]\t- Toggle marks: unmark the marked and mark the unmarked + +\\[bmkp-bmenu-mark-autofile-bookmarks]\t- Mark autofile bookmarks +\\[bmkp-bmenu-mark-autonamed-bookmarks]\t- Mark autonamed bookmarks +\\[bmkp-bmenu-mark-temporary-bookmarks]\t- Mark temporary bookmarks +\\[bmkp-bmenu-mark-lighted-bookmarks]\t- Mark highlighted bookmarks (requires `bookmark+-lit.el) + +\\[bmkp-bmenu-mark-non-file-bookmarks]\t- Mark non-file (i.e. buffer) bookmarks +\\[bmkp-bmenu-mark-dired-bookmarks]\t- Mark Dired bookmarks +\\[bmkp-bmenu-mark-file-bookmarks]\t- Mark file & directory bookmarks (`C-u': local only) +\\[bmkp-bmenu-mark-gnus-bookmarks]\t- Mark Gnus bookmarks +\\[bmkp-bmenu-mark-info-bookmarks]\t- Mark Info bookmarks +\\[bmkp-bmenu-mark-icicles-search-hits-bookmarks]\t- Mark Icicles search-hits bookmarks +\\[bmkp-bmenu-mark-non-invokable-bookmarks]\t- Mark non-invokable bookmarks +\\[bmkp-bmenu-mark-image-bookmarks]\t- Mark image-file bookmarks +\\[bmkp-bmenu-mark-desktop-bookmarks]\t- Mark desktop bookmarks +\\[bmkp-bmenu-mark-man-bookmarks]\t- Mark `man' page bookmarks (that's `M' twice, not Meta-M) +\\[bmkp-bmenu-mark-orphaned-local-file-bookmarks]\t- Mark orphaned local file/dir bookmarks (`C-u': \ +remote also) +\\[bmkp-bmenu-mark-region-bookmarks]\t- Mark region bookmarks +\\[bmkp-bmenu-mark-function-bookmarks]\t- Mark function bookmarks +\\[bmkp-bmenu-mark-url-bookmarks]\t- Mark URL bookmarks +\\[bmkp-bmenu-mark-variable-list-bookmarks]\t- Mark variable-list bookmarks +\\[bmkp-bmenu-mark-w3m-bookmarks]\t- Mark W3M (URL) bookmarks +\\[bmkp-bmenu-mark-snippet-bookmarks]\t- Mark snippet bookmarks +\\[bmkp-bmenu-mark-bookmark-file-bookmarks]\t- Mark bookmark-file bookmarks +\\[bmkp-bmenu-mark-bookmark-list-bookmarks]\t- Mark bookmark-list bookmarks + + +Modify, Delete Bookmarks +------------------------ + +\(See also `Tags', next.) + +\\[bmkp-bmenu-edit-bookmark-name-and-location]\t- Rename or relocate bookmark +\\[bookmark-bmenu-relocate]\t- Relocate bookmark +\\[bmkp-bmenu-relocate-marked]\t- Relocate marked bookmarks +\\[bmkp-bmenu-edit-tags]\t- Edit bookmark's tags +\\[bookmark-bmenu-edit-annotation]\t- Edit bookmark's annotation +\\[bmkp-bmenu-edit-annotations-for-marked]\t- Edit annotations of marked bookmarks (`C-u': all) +\\[bmkp-bmenu-edit-bookmark-record]\t- Edit internal Lisp record for bookmark +\\[bmkp-bmenu-edit-marked]\t- Edit internal Lisp records of marked bookmarks (`C-u': all) +\\[bmkp-bmenu-toggle-temporary]\t- Toggle temporary/savable status of bookmark +\\[bmkp-bmenu-toggle-marked-temporary/savable]\t- Toggle temporary/savable status of marked bookmarks +\\[bmkp-delete-all-temporary-bookmarks]\t- Delete all temp bookmarks +\\[bookmark-bmenu-execute-deletions]\t- Delete (visible) bookmarks flagged `D' +\\[bmkp-bmenu-delete-marked]\t- Delete (visible) bookmarks marked `>' + + +Bookmark Tags +------------- + +Here: + +\\[bmkp-bmenu-copy-tags]\t- Copy tags from this bookmark (for subsequent pasting) +\\[bmkp-bmenu-paste-add-tags]\t- Paste tags (copied from another) to this bookmark +\\[bmkp-bmenu-paste-replace-tags]\t- Replace tags for this bookmark (with those copied) +\\[bmkp-add-tags]\t- Add some tags to a bookmark +\\[bmkp-remove-tags]\t- Remove some tags from a bookmark (`C-u': from all bookmarks) +\\[bmkp-remove-all-tags]\t- Remove all tags from a bookmark +\\[bmkp-remove-tags-from-all]\t- Remove some tags from all bookmarks +\\[bmkp-rename-tag]\t- Rename a tag in all bookmarks +\\[bmkp-list-all-tags]\t- List all tags used in any bookmarks (`C-u': show tag values) +\\[bmkp-bmenu-list-tags-of-marked]\t- List tags used in marked bookmarks (`C-u': show tag values) +\\[bmkp-bmenu-edit-tags]\t- Edit bookmark's tags +\\[bmkp-bmenu-set-tag-value]\t- Set the value of a tag (as attribute) + +\\[bmkp-bmenu-set-tag-value-for-marked]\t- Set value of a tag, for each marked bookmark (`C-u': all) +\\[bmkp-bmenu-paste-add-tags-to-marked]\t- Add tags copied from a bookmark to those marked (`C-u': all) +\\[bmkp-bmenu-paste-replace-tags-for-marked]\t- Replace tags of marked with copied tags \ + (`C-u': all) +\\[bmkp-bmenu-add-tags-to-marked]\t- Add some tags to the marked bookmarks (`C-u': all) +\\[bmkp-bmenu-remove-tags-from-marked]\t- Remove some tags from the marked bookmarks (`C-u': all) + +\\[bmkp-bmenu-mark-bookmarks-tagged-regexp]\t- Mark bookmarks having at least one \ +tag that matches a regexp +\\[bmkp-bmenu-mark-bookmarks-tagged-some]\t- Mark bookmarks having at least one tag \ +in a set (OR) +\\[bmkp-bmenu-mark-bookmarks-tagged-all]\t- Mark bookmarks having all of the tags \ +in a set (AND) +\\[bmkp-bmenu-mark-bookmarks-tagged-none]\t- Mark bookmarks not having any of the tags \ +in a set (NOT OR) +\\[bmkp-bmenu-mark-bookmarks-tagged-not-all]\t- Mark bookmarks not having all of the \ +tags in a set (NOT AND) + +\\[bmkp-bmenu-unmark-bookmarks-tagged-regexp]\t- Unmark bookmarks having a \ +tag that matches a regexp +\\[bmkp-bmenu-unmark-bookmarks-tagged-some]\t- Unmark bookmarks having at least one \ +tag in a set (OR) +\\[bmkp-bmenu-unmark-bookmarks-tagged-all]\t- Unmark bookmarks having all of the tags \ +in a set (AND) +\\[bmkp-bmenu-unmark-bookmarks-tagged-none]\t- Unmark bookmarks not having any tags \ +in a set (NOT OR) +\\[bmkp-bmenu-unmark-bookmarks-tagged-not-all]\t- Unmark bookmarks not having all tags \ +in a set (NOT AND) + +Anywhere: + +\\\ +\\[bmkp-list-all-tags]\t- List all tags +\\[bmkp-edit-tags]\t- Edit the tags of a bookmark +\\[bmkp-rename-tag]\t- Rename a tag (everywhere) +\\[bmkp-copy-tags]\t- Copy tags from a bookmark (for subsequent pasting) +\\[bmkp-paste-add-tags]\t- Add (paste) tags copied from a bookmark +\\[bmkp-paste-replace-tags]\t- Replace (paste) a bookmark's tags with copied tags +\\[bmkp-add-tags]\t- Add some tags to a bookmark +\\[bmkp-remove-tags]\t- Remove some tags from a bookmark +\\[bmkp-remove-all-tags]\t- Remove ALL tags from a bookmark +\\[bmkp-remove-tags-from-all]\t- Remove some tags from ALL bookmarks +\\[bmkp-tag-a-file]\t- Add tags to a file (create/update autofile bookmark) +\\[bmkp-untag-a-file]\t- Remove tags from a file (an autofile bookmark) +\\[bmkp-set-tag-value]\t- Set a tag value for a bookmark +\\[bmkp-set-tag-value-for-navlist]\t- Set a tag value for each bookmark in navlist +\\ + + +Bookmark Highlighting +--------------------- + +\\[bmkp-bmenu-show-only-lighted-bookmarks]\t- Show only the highlighted bookmarks +\\[bmkp-bmenu-set-lighting]\t- Set highlighting for bookmark +\\[bmkp-bmenu-set-lighting-for-marked]\t- Set highlighting for marked bookmarks +\\[bmkp-bmenu-light]\t- Highlight bookmark +\\[bmkp-bmenu-unlight]\t- Unhighlight bookmark +\\[bmkp-bmenu-mark-lighted-bookmarks]\t- Mark the highlighted bookmarks +\\[bmkp-bmenu-light-marked]\t- Highlight the marked bookmarks +\\[bmkp-bmenu-unlight-marked]\t- Unhighlight the marked bookmarks +\\[bmkp-light-bookmark-this-buffer]\t- Highlight a bookmark in current buffer +\\[bmkp-unlight-bookmark-this-buffer]\t- Unhighlight a bookmark in current buffer +\\[bmkp-light-bookmarks]\t- Highlight bookmarks (see prefix arg) +\\[bmkp-unlight-bookmarks]\t- Unhighlight bookmarks (see prefix arg) +\\[bmkp-bookmarks-lighted-at-point]\t- List bookmarks highlighted at point +\\[bmkp-unlight-bookmark-here]\t- Unhighlight a bookmark at point or on same line +\\[bmkp-lighted-jump-other-window]\t- Jump to a highlighted bookmark (other window) + + +Sort `*Bookmark List*' (`s C-h' to see this) +---------------------- + +\(Repeat to cycle normal/reversed/off, except as noted.) + +\\[bmkp-reverse-sort-order]\t- Reverse current sort direction (repeat to toggle) +\\[bmkp-reverse-multi-sort-order]\t- Complement sort predicate decisions (repeat \ +to toggle) +\\[bmkp-bmenu-change-sort-order-repeat]\t- Cycle sort orders (repeat \ +to cycle) + +\\[bmkp-bmenu-sort-marked-before-unmarked]\t- Sort marked (`>') bookmarks first +\\[bmkp-bmenu-sort-flagged-before-unflagged]\t- Sort flagged (`D') bookmarks first +\\[bmkp-bmenu-sort-modified-before-unmodified]\t- Sort modified (`*') bookmarks first +\\[bmkp-bmenu-sort-tagged-before-untagged]\t- Sort tagged (`t') bookmarks first +\\[bmkp-bmenu-sort-annotated-before-unannotated]\t- Sort annotated (`a') bookmarks first + +\\[bmkp-bmenu-sort-by-creation-time]\t- Sort by bookmark creation time +\\[bmkp-bmenu-sort-by-last-buffer-or-file-access]\t- Sort by last buffer or file \ +access +\\[bmkp-bmenu-sort-by-last-bookmark-access]\t- Sort by last bookmark access time +\\[bmkp-bmenu-sort-by-Gnus-thread]\t- Sort by Gnus thread: group, article, message +\\[bmkp-bmenu-sort-by-Info-node-name]\t- Sort by Info manual, node, position in node +\\[bmkp-bmenu-sort-by-Info-position]\t- Sort by Info manual, position in manual +\\[bmkp-bmenu-sort-by-bookmark-type]\t- Sort by bookmark type +\\[bmkp-bmenu-sort-by-bookmark-name]\t- Sort by bookmark name +\\[bmkp-bmenu-sort-by-url]\t- Sort by URL +\\[bmkp-bmenu-sort-by-bookmark-visit-frequency]\t- Sort by bookmark visit frequency + +\\[bmkp-bmenu-sort-by-last-local-file-access]\t- Sort by last local file access +\\[bmkp-bmenu-sort-by-local-file-type]\t- Sort by local file type: file, symlink, dir +\\[bmkp-bmenu-sort-by-file-name]\t- Sort by file name +\\[bmkp-bmenu-sort-by-local-file-size]\t- Sort by local file size +\\[bmkp-bmenu-sort-by-last-local-file-update]\t- Sort by last local file update (edit) + + +Hide/Show (Filtering `*Bookmark List*') +--------------------------------------- + +\\[bmkp-bmenu-show-all]\t- Show all bookmarks +\\[bmkp-bmenu-toggle-show-only-marked]\t- Toggle showing only marked bookmarks +\\[bmkp-bmenu-toggle-show-only-unmarked]\t- Toggle showing only unmarked bookmarks + +\\[bmkp-bmenu-show-only-autonamed-bookmarks]\t- Show only autonamed bookmarks +\\[bmkp-bmenu-show-only-autofile-bookmarks]\t- Show only autofile bookmarks +\\[bmkp-bmenu-show-only-temporary-bookmarks]\t- Show only temporary bookmarks + +\\[bmkp-bmenu-show-only-non-file-bookmarks]\t- Show only non-file (i.e. buffer) bookmarks +\\[bmkp-bmenu-show-only-dired-bookmarks]\t- Show only Dired bookmarks +\\[bmkp-bmenu-show-only-file-bookmarks]\t- Show only file & directory bookmarks (`C-u': local only) +\\[bmkp-bmenu-show-only-gnus-bookmarks]\t- Show only Gnus bookmarks +\\[bmkp-bmenu-show-only-info-bookmarks]\t- Show only Info bookmarks +\\[bmkp-bmenu-show-only-icicles-search-hits-bookmarks]\t- Show only Icicles search-hits bookmarks +\\[bmkp-bmenu-show-only-non-invokable-bookmarks]\t- Show only non-invokable bookmarks +\\[bmkp-bmenu-show-only-image-bookmarks]\t- Show only image-file bookmarks +\\[bmkp-bmenu-show-only-orphaned-local-file-bookmarks]\t- Show only orphaned local file \ +bookmarks (`C-u': remote also) +\\[bmkp-bmenu-show-only-desktop-bookmarks]\t- Show only desktop bookmarks +\\[bmkp-bmenu-show-only-man-bookmarks]\t- Show only `man' page bookmarks +\\[bmkp-bmenu-show-only-region-bookmarks]\t- Show only region bookmarks +\\[bmkp-bmenu-show-only-function-bookmarks]\t- Show only function bookmarks +\\[bmkp-bmenu-show-only-url-bookmarks]\t- Show only URL bookmarks +\\[bmkp-bmenu-show-only-eww-bookmarks]\t- Show only EWW bookmarks +\\[bmkp-bmenu-show-only-w3m-bookmarks]\t- Show only W3M bookmarks +\\[bmkp-bmenu-show-only-variable-list-bookmarks]\t- Show only variable-list bookmarks +\\[bmkp-bmenu-show-only-tagged-bookmarks]\t- Show only tagged bookmarks +\\[bmkp-bmenu-show-only-untagged-bookmarks]\t- Show only untagged bookmarks +\\[bmkp-bmenu-show-only-snippet-bookmarks]\t- Show only snippet bookmarks +\\[bmkp-bmenu-show-only-bookmark-file-bookmarks]\t- Show only bookmark-file bookmarks +\\[bmkp-bmenu-show-only-bookmark-list-bookmarks]\t- Show only bookmark-list bookmarks + +\\[bmkp-bmenu-filter-annotation-incrementally]\t- Incrementally show bookmarks whose \ +annotations match regexp +\\[bmkp-bmenu-filter-bookmark-name-incrementally]\t- Incrementally show only bookmarks \ +whose names match a regexp +\\[bmkp-bmenu-filter-file-name-incrementally]\t- Incrementally show only bookmarks whose \ +files match a regexp +\\[bmkp-bmenu-filter-tags-incrementally]\t- Incrementally show only bookmarks whose tags \ +match a regexp + + +Omit/Un-omit (`*Bookmark List*') +-------------------------------- + +\\[bmkp-bmenu-show-only-omitted-bookmarks]\t- Show (only) the omitted bookmarks +\\[bmkp-bmenu-show-all]\t- Show the un-omitted bookmarks (all) +\\[bmkp-bmenu-omit/unomit-marked]\t- Omit the marked bookmarks; un-omit them if after \ +`\\[bmkp-bmenu-show-only-omitted-bookmarks]' +\\[bmkp-unomit-all]\t- Un-omit all omitted bookmarks + + +Define Commands for `*Bookmark List*' +------------------------------------- + +\\[bmkp-bmenu-define-command]\t- Define a command to restore the current sort order & filter +\\[bmkp-bmenu-define-full-snapshot-command]\t- Define a command to restore current bookmark list +\\[bmkp-define-tags-sort-command]\t- Define a command to sort bookmarks by tags +\\[bmkp-bmenu-define-jump-marked-command]\t- Define a command to jump to a bookmark that is \ +now marked + + +Options for `*Bookmark List*' +----------------------------- + +bookmark-bmenu-file-column - Bookmark width if files are shown +bookmark-bmenu-toggle-filenames - Show filenames initially? + +bmkp-bmenu-omitted-bookmarks - List of omitted bookmarks +bmkp-bmenu-state-file - File to save bookmark-list state + (\"home\") nil: do not save/restore +bmkp-sort-comparer - Initial sort +bmkp-sort-orders-for-cycling-alist - Sort orders that `\\[bmkp-bmenu-change-sort-order-repeat]'... cycles + + +Other Options +------------- + +bookmark-automatically-show-annotations - Show annotation when visit? +bookmark-completion-ignore-case - Case-sensitive completion? +bookmark-default-file - File to save bookmarks in +bookmark-menu-length - Max size of bookmark-name menu item +bookmark-save-flag - Whether and when to save +bookmark-use-annotations - Edit annotation when set bookmark? +bookmark-version-control - Numbered backups of bookmark file? + +bmkp-autoname-format - Format of autonamed bookmark name +bmkp-last-as-first-bookmark-file - Whether to start with last b. file +bmkp-crosshairs-flag - Highlight position when visit? +bmkp-menu-popup-max-length - Use menus to choose bookmarks? +bmkp-save-new-location-flag - Save if bookmark relocated? +bmkp-sequence-jump-display-function - How to display a sequence +bmkp-sort-comparer - Predicates for sorting bookmarks +bmkp-su-or-sudo-regexp - Bounce-show each end of region? +bmkp-this-file/buffer-cycle-sort-comparer - cycling sort for here +bmkp-use-region - Activate saved region when visit?" + (kill-all-local-variables) + (use-local-map bookmark-bmenu-mode-map) + (setq truncate-lines t + buffer-read-only t + major-mode 'bookmark-bmenu-mode + mode-name (if bmkp-temporary-bookmarking-mode "TEMPORARY Bookmarking" "Bookmarks")) + (if (fboundp 'run-mode-hooks) + (run-mode-hooks 'bookmark-bmenu-mode-hook) + (run-hooks 'bookmark-bmenu-mode-hook))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Corrected (rewrote). Toggle var first (unless SHOW). Call fn according to the var (& to SHOW). +;; 2. Added optional arg NO-MSG-P. +;; +(defun bookmark-bmenu-toggle-filenames (&optional show no-msg-p) + "Toggle whether filenames are shown in the bookmark list. +Toggle the value of `bookmark-bmenu-toggle-filenames', unless SHOW is +non-nil. +Optional argument SHOW means show them unconditionally. + +Non-nil optional arg NO-MSG-P means do not show progress messages." + (interactive) + (unless show (setq bookmark-bmenu-toggle-filenames (not bookmark-bmenu-toggle-filenames))) + (let ((bookmark-bmenu-toggle-filenames (or show bookmark-bmenu-toggle-filenames))) + (if bookmark-bmenu-toggle-filenames + (bookmark-bmenu-show-filenames nil no-msg-p) + (bookmark-bmenu-hide-filenames nil no-msg-p)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Put `mouse-face' on whole line, with the same help-echo as for the bookmark name. +;; 2. Correct FORCE behavior. +;; 3. Correct doc string. +;; 4. Added optional arg NO-MSG-P and progress message. +;; 5. Fit one-window frame. +;; +(defun bookmark-bmenu-show-filenames (&optional force no-msg-p) + "Show file names if `bookmark-bmenu-toggle-filenames' is non-nil. +Otherwise do nothing, except non-nil optional argument FORCE has the +same effect as non-nil `bookmark-bmenu-toggle-filenames'. FORCE is +mainly for debugging. +Non-nil optional arg NO-MSG-P means do not show progress messages." + (when (or force bookmark-bmenu-toggle-filenames) + (unless no-msg-p (message "Showing file names...")) + (with-buffer-modified-unmodified + (save-excursion + (save-window-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (setq bookmark-bmenu-hidden-bookmarks ()) + (let ((inhibit-read-only t)) + (while (< (point) (point-max)) + (let ((bmk (bookmark-bmenu-bookmark))) + (setq bookmark-bmenu-hidden-bookmarks (cons bmk bookmark-bmenu-hidden-bookmarks)) + (move-to-column bookmark-bmenu-file-column t) + (delete-region (point) (line-end-position)) + (insert " ") + (bookmark-insert-location bmk t) ; Pass the NO-HISTORY arg. + (when (if (fboundp 'display-color-p) ; Emacs 21+. + (and (display-color-p) (display-mouse-p)) + window-system) + (let ((help (get-text-property (+ bmkp-bmenu-marks-width (line-beginning-position)) + 'help-echo))) + (put-text-property (+ bmkp-bmenu-marks-width (line-beginning-position)) + (point) 'mouse-face 'highlight) + (when help (put-text-property (+ bmkp-bmenu-marks-width (line-beginning-position)) + (point) 'help-echo help)))) + (forward-line 1))))))) + (unless no-msg-p (message "Showing file names...done")) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Add text properties when hiding filenames. +;; 2. Do not set or use `bookmark-bmenu-bookmark-column' - use `bmkp-bmenu-marks-width' always. +;; 3. Correct FORCE behavior. +;; 4. Correct doc string. +;; 5. Added optional arg NO-MSG-P and progress message. +;; 6. Fit one-window frame. +;; +(defun bookmark-bmenu-hide-filenames (&optional force no-msg-p) + "Hide filenames if `bookmark-bmenu-toggle-filenames' is nil. +Otherwise do nothing, except non-nil optional argument FORCE has the +same effect as nil `bookmark-bmenu-toggle-filenames'. FORCE is mainly +for debugging. +Non-nil optional arg NO-MSG-P means do not show progress messages." + (when (or force (not bookmark-bmenu-toggle-filenames)) + (unless no-msg-p (message "Hiding file names...")) + (with-buffer-modified-unmodified + (save-excursion + (save-window-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (setq bookmark-bmenu-hidden-bookmarks (nreverse bookmark-bmenu-hidden-bookmarks)) + (let ((max-width 0)) + (dolist (name bookmark-bmenu-hidden-bookmarks) + (setq max-width (max max-width (string-width name)))) + (setq max-width (+ max-width bmkp-bmenu-marks-width)) + (save-excursion + (let ((inhibit-read-only t)) + (while bookmark-bmenu-hidden-bookmarks + (move-to-column bmkp-bmenu-marks-width t) + (bookmark-kill-line) + (let ((name (car bookmark-bmenu-hidden-bookmarks)) + (start (point)) + end) + (insert name) + (move-to-column max-width t) + (setq end (point)) + (bmkp-bmenu-propertize-item name start end)) + (setq bookmark-bmenu-hidden-bookmarks (cdr bookmark-bmenu-hidden-bookmarks)) + (forward-line 1)))))))) + (unless no-msg-p (message "Hiding file names...done")) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Prefix arg reverses `bmkp-use-region'. +;; 2. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-1-window "bookmark+") +(defun bookmark-bmenu-1-window (&optional flip-use-region-p) ; Bound to `1' in bookmark list + "Select this line's bookmark, alone, in full frame. +See `bookmark-jump' for info about the prefix arg." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (bmkp-jump-1 (bookmark-bmenu-bookmark) 'pop-to-buffer flip-use-region-p) + (bury-buffer (other-buffer)) + (delete-other-windows)) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Prefix arg reverses `bmkp-use-region'. +;; 2. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-2-window "bookmark+") +(defun bookmark-bmenu-2-window (&optional flip-use-region-p) ; Bound to `2' in bookmark list + "Select this line's bookmark, with previous buffer in second window. +See `bookmark-jump' for info about the prefix arg." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bookmark-name (bookmark-bmenu-bookmark)) + (menu (current-buffer)) + (pop-up-windows t)) + (delete-other-windows) + (bmkp--pop-to-buffer-same-window (other-buffer)) + ;; (let ((bookmark-automatically-show-annotations nil)) ; $$$$$$ Needed? + (bmkp-jump-1 bookmark-name 'pop-to-buffer flip-use-region-p) + (bury-buffer menu))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Prefix arg reverses `bmkp-use-region'. +;; 2. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-this-window "bookmark+") +(defun bookmark-bmenu-this-window (&optional flip-use-region-p) ; Bound to `RET' in bookmark list + "Select this line's bookmark in this window. +See `bookmark-jump' for info about the prefix arg." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bookmark-name (bookmark-bmenu-bookmark))) + (bmkp-jump-1 bookmark-name 'bmkp--pop-to-buffer-same-window flip-use-region-p))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Use `pop-to-buffer', not `switch-to-buffer-other-window'. +;; 2. Prefix arg reverses `bmkp-use-region'. +;; 3. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-other-window "bookmark+") +(defun bookmark-bmenu-other-window (&optional flip-use-region-p) ; Bound to `o' in bookmark list + "Select this line's bookmark in other window. Show `*Bookmark List*' still. +See `bookmark-jump' for info about the prefix arg." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bookmark-name (bookmark-bmenu-bookmark))) + ;; (bookmark-automatically-show-annotations t)) ; $$$$$$ Needed? + (bookmark-jump-other-window bookmark-name flip-use-region-p))) + + +;; REPLACES ORIGINAL in `bookmark.el' (Emacs 27+). +;; +;; 1. Use `pop-to-buffer', not `view-buffer-other-frame'. +;; 2. Prefix arg reverses `bmkp-use-region'. +;; 3. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-other-window "bookmark+") +(defun bookmark-bmenu-other-frame (&optional flip-use-region-p) ; Bound to `j 5' in bookmark list + "Select this line's bookmark in another frame. +See `bookmark-jump' for info about the prefix arg." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bookmark-name (bookmark-bmenu-bookmark))) + ;; (bookmark-automatically-show-annotations t)) ; $$$$$$ Needed? + (bookmark-jump-other-frame bookmark-name flip-use-region-p))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Prefix arg reverses `bmkp-use-region'. +;; 2. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-switch-other-window "bookmark+") +(defun bookmark-bmenu-switch-other-window (&optional flip-use-region-p) ; Bound to `C-o' in bookmark list + "Make the other window select this line's bookmark. +The current window remains selected. +See `bookmark-jump' for info about the prefix arg." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bookmark-name (bookmark-bmenu-bookmark)) + (pop-up-windows t) + (same-window-buffer-names ()) + (same-window-regexps ())) + ;; (bookmark-automatically-show-annotations t)) ; $$$$$$ Needed? + (bmkp-jump-1 bookmark-name 'display-buffer flip-use-region-p))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Prefix arg reverses `bmkp-use-region'. +;; 2. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-other-window-with-mouse "bookmark+") +(defun bookmark-bmenu-other-window-with-mouse (event &optional flip-use-region-p) + "Select clicked bookmark in other window. Show `*Bookmark List*' still. +See `bookmark-jump' for info about the prefix arg." + (interactive "e\nP") + (with-current-buffer (window-buffer (posn-window (event-end event))) + (save-excursion (goto-char (posn-point (event-end event))) + (bookmark-bmenu-other-window flip-use-region-p)))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg MSG-P. +;; 2. Call `bookmark-show-annotation' with arg MSG-P. +;; 3. Raise error if not in buffer `*Bookmark List*'. +;; 4. Doc string reflects enhanced behavior of `bookmark-show-annotation'. +;; +;;;###autoload (autoload 'bookmark-bmenu-show-annotation "bookmark+") +(defun bookmark-bmenu-show-annotation (&optional msg-p) ; Bound to `a a' in bookmark list + "Show the annotation for the current bookmark, or follow it if external. +If the annotation is external then jump to its destination. +Non-interactively, non-nil MSG-P means display messages." + (interactive "p") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bmk (bookmark-bmenu-bookmark))) + (unless bmk (error "No bookmark here")) + (bookmark-show-annotation bmk msg-p))) + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Added optional arg MARKEDP: handle bookmarks marked `>', not just those flagged `D'. +;; 2. Added optional arg NO-CONFIRM-P. +;; 3. Delete bookmark on current line (after confirmation) if none are flagged/marked. +;; 4. Inhibit saving until all are deleted, then save all. This is because the Bookmark+ version of +;; `bookmark-save' refreshes the bookmark list display, and that removes `D' flags. +;; 5. Use `bmkp-get-bookmark' instead of `bookmark-get-bookmark', so we can get the right bookmarks when +;; they have names with property `bmkp-full-record'. But don't require that they have names, so +;; calls from vanilla or other code won't be bothered. +;; 6. Use `bookmark-bmenu-surreptitiously-rebuild-list', instead of using +;; `bookmark-bmenu-list', updating the modification count, and saving. +;; 7. Update `bmkp-latest-bookmark-alist' to reflect the deletions. +;; 8. Pass full bookmark, not name, to `delete' (and do not use `assoc'). +;; 9. Use `bmkp-bmenu-goto-bookmark-named'. +;; 10. Added status messages. +;; 11. Raise error if not in buffer `*Bookmark List*'. +;; +;;;###autoload (autoload 'bookmark-bmenu-execute-deletions "bookmark+") +(defun bookmark-bmenu-execute-deletions (&optional markedp no-confirm-p) ; Bound to `x' in bookmark list + "Delete (visible) bookmarks flagged `D', without confirmation. +With a prefix argument, delete the bookmarks marked `>' instead, but +only after confirmation. + +If NO bookmarks are flagged or marked (depending on whether a prefix +arg was used), then delete the bookmark on this line, but only after +confirmation. + +Non-interactively, optional arg NO-CONFIRM-P non-nil means do not ask +for confirmation." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (if (and (null (if markedp bmkp-bmenu-marked-bookmarks bmkp-flagged-bookmarks)) + (bookmark-bmenu-bookmark)) + (if (progn (let ((visible-bell t) + (minibuffer-prompt-properties (append minibuffer-prompt-properties + '(face bmkp-*-mark)))) + (ding) (ding) + (yes-or-no-p "DELETE THIS bookmark "))) + (bookmark-delete (bookmark-bmenu-bookmark)) + (message "OK, not deleted")) + (if (or (not markedp) + no-confirm-p + (yes-or-no-p "Delete bookmarks marked `>' (not `D') ")) + (let* ((mark-type (if markedp "^>" "^D")) + (o-str (and (not (bmkp-looking-at-p mark-type)) (bookmark-bmenu-bookmark))) + (o-point (point)) + (count 0)) + (message "Deleting bookmarks...") + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (while (re-search-forward mark-type (point-max) t) + (let* ((bmk-name (bookmark-bmenu-bookmark)) + (bmk (bmkp-get-bookmark bmk-name nil 'NO-NAME-CHECK-P))) + ;; Inhibit saving until all are deleted, then do it once. Otherwise, some might not be + ;; deleted, because `bookmark-save' refreshes the list, which removes `D' flags. + (let ((bookmark-save-flag nil)) (bookmark-delete bmk-name 'BATCHP)) + ;; Count is misleading if the bookmark is not really in `bookmark-alist'. + (setq count (1+ count) + bmkp-latest-bookmark-alist (delete bmk bmkp-latest-bookmark-alist)))) + (bmkp-maybe-save-bookmarks) ; Do it now. + (if (<= count 0) + (message (if markedp "No marked bookmarks" "No bookmarks flagged for deletion")) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (message "Deleted %d bookmarks" count)) + (if o-str + (bmkp-bmenu-goto-bookmark-named o-str) + (goto-char o-point) + (beginning-of-line))) + (message "OK, nothing deleted")))) + + + +;; REPLACES ORIGINAL in `bookmark.el'. +;; +;; 1. Do not call `bookmark-bmenu-list' (it was already called). +;; 2. Raise error if not in buffer `*Bookmark List*'. +;; 3. Use `bmkp-bmenu-goto-bookmark-named' instead of just searching for name. +;; +;;;###autoload (autoload 'bookmark-bmenu-rename "bookmark+") +(defun bookmark-bmenu-rename () ; Bound to `r' in bookmark list + "Rename bookmark on current line. Prompts for a new name." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((newname (bookmark-rename (bookmark-bmenu-bookmark)))) (bmkp-bmenu-goto-bookmark-named newname))) + +;;(@* "Bookmark+ Functions (`bmkp-*')") +;;; Bookmark+ Functions (`bmkp-*') ----------------------------------- + + +;;(@* "Menu-List (`*-bmenu-*') Filter Commands") +;; *** Menu-List (`*-bmenu-*') Filter Commands *** + +;; `bmkp-bmenu-show-only-autonamed-bookmarks', +;; `bmkp-bmenu-show-only-non-file-bookmarks', +;; `bmkp-bmenu-show-only-dired-bookmarks', +;; `bmkp-bmenu-show-only-eww-bookmarks' (Emacs 25+), +;; `bmkp-bmenu-show-only-function-bookmarks', +;; `bmkp-bmenu-show-only-gnus-bookmarks', +;; `bmkp-bmenu-show-only-icicles-search-hits-bookmarks', +;; `bmkp-bmenu-show-only-non-invokable-bookmarks', +;; `bmkp-bmenu-show-only-image-bookmarks', +;; `bmkp-bmenu-show-only-info-bookmarks', +;; `bmkp-bmenu-show-only-desktop-bookmarks', +;; `bmkp-bmenu-show-only-man-bookmarks', +;; `bmkp-bmenu-show-only-region-bookmarks', +;; `bmkp-bmenu-show-only-tagged-bookmarks', +;; `bmkp-bmenu-show-only-untagged-bookmarks', +;; `bmkp-bmenu-show-only-url-bookmarks', +;; `bmkp-bmenu-show-only-variable-list-bookmarks', +;; `bmkp-bmenu-show-only-snippet-bookmarks', +;; `bmkp-bmenu-show-only-w3m-bookmarks', +;; `bmkp-bmenu-show-only-temporary-bookmarks', +;; `bmkp-bmenu-show-only-bookmark-file-bookmarks', +;; `bmkp-bmenu-show-only-bookmark-list-bookmarks', + + +;; The simple ones are defined using macro `bmkp-define-show-only-command'. +;; +;;;###autoload (autoload 'bmkp-bmenu-show-only-autonamed-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-non-file-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-dired-bookmarks "bookmark+") + +;; ;;;###autoload (autoload 'bmkp-bmenu-show-only-eww-bookmarks "bookmark+") + +;;;###autoload (autoload 'bmkp-bmenu-show-only-function-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-gnus-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-icicles-search-hits-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-non-invokable-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-image-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-info-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-desktop-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-man-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-region-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-tagged-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-untagged-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-url-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-variable-list-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-snippet-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-w3m-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-temporary-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-bookmark-file-bookmarks "bookmark+") +;;;###autoload (autoload 'bmkp-bmenu-show-only-bookmark-list-bookmarks "bookmark+") + +;; Bindings indicated are in `*Bookmark List*'. +(bmkp-define-show-only-command autonamed "Display (only) the autonamed bookmarks." + bmkp-autonamed-alist-only) ; `# S' +(bmkp-define-show-only-command non-file "Display (only) the non-file (buffer) bookmarks." + bmkp-non-file-alist-only) ; `B S' +(bmkp-define-show-only-command dired "Display (only) the Dired bookmarks." + bmkp-dired-alist-only) ; `M-d M-s' +(bmkp-define-show-only-command gnus "Display (only) the gnus bookmarks." + bmkp-gnus-alist-only) ; `G S' +(bmkp-define-show-only-command "icicles search-hits" "Display (only) the Icicles search-hits bookmarks." + bmkp-icicles-search-hits-alist-only) ; `i S' +(bmkp-define-show-only-command image "Display (only) the image-file bookmarks." + bmkp-image-alist-only) ; `M-I M-S' +(bmkp-define-show-only-command info "Display (only) the Info bookmarks." + bmkp-info-alist-only) ; `I S' +(bmkp-define-show-only-command desktop "Display (only) the desktop bookmarks." + bmkp-desktop-alist-only) ; `K S' +(bmkp-define-show-only-command man-page "Display (only) the `man' page bookmarks." + bmkp-man-alist-only) ; `M S' +(bmkp-define-show-only-command function "Display (only) the function bookmarks." + bmkp-function-alist-only) ; `Q S' +(bmkp-define-show-only-command region "Display (only) the bookmarks that record a region." + bmkp-region-alist-only) ; `R S' +(bmkp-define-show-only-command tagged "Display (only) the bookmarks that have tags." + bmkp-tagged-alist-only) ; `T S' +(bmkp-define-show-only-command untagged "Display (only) the bookmarks that do not have tags." + bmkp-untagged-alist-only) ; Not bound +(bmkp-define-show-only-command url "Display (only) the url bookmarks." + bmkp-url-alist-only) ; `M-u M-s' +(bmkp-define-show-only-command variable-list "Display (only) the variable-list bookmarks." + bmkp-variable-list-alist-only) ; `V S' +(bmkp-define-show-only-command snippet "Display (only) the snippet bookmarks." + bmkp-snippet-alist-only) ; `w S' +(when (fboundp 'bmkp-eww-bookmark-p) ; Emacs 25+ + (bmkp-define-show-only-command eww "Display (only) the EWW URL bookmarks." + bmkp-eww-alist-only)) ; `W E S' +(bmkp-define-show-only-command w3m "Display (only) the W3M URL bookmarks." + bmkp-w3m-alist-only) ; `W 3 S' +(bmkp-define-show-only-command temporary "Display (only) the temporary bookmarks." + bmkp-temporary-alist-only) ; `X S' +(bmkp-define-show-only-command bookmark-file "Display (only) the bookmark-file bookmarks." + bmkp-bookmark-file-alist-only) ; `Y S' +(bmkp-define-show-only-command bookmark-list "Display (only) the bookmark-list bookmarks." + bmkp-bookmark-list-alist-only) ; `Z S' + +;;;###autoload (autoload 'bmkp-bmenu-show-all "bookmark+") +(defun bmkp-bmenu-show-all () ; Bound to `.' in bookmark list + "Show all bookmarks known to the bookmark list (aka \"menu list\"). +Omitted bookmarks are not shown, however. +Also, this does not revert the bookmark list, to bring it up to date. +To revert the display from the current list, use `\\\ +\\[bmkp-bmenu-refresh-menu-list]'. +To revert the list and display from the bookmark file, use `C-u \\[bmkp-bmenu-refresh-menu-list]'." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-bmenu-filter-function nil + bmkp-bmenu-title "All Bookmarks" + bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list) + (when (interactive-p) (bmkp-msg-about-sort-order (bmkp-current-sort-order) "All bookmarks are shown"))) + +;;;###autoload (autoload 'bmkp-bmenu-show-only-autofile-bookmarks "bookmark+") +(defun bmkp-bmenu-show-only-autofile-bookmarks (&optional arg) ; Bound to `A S' in bookmark list + "Display (only) the autofile bookmarks. +This means bookmarks whose names are the same as the nondirectory part +of their file names (or their `directory-file-name', for directories). + +But with a prefix arg you are prompted for a prefix that each bookmark +name must have." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-bmenu-filter-function (if (not arg) + 'bmkp-autofile-alist-only + (let ((prefix (read-string "Prefix for bookmark names: " + nil nil ""))) + `(lambda () (bmkp-autofile-alist-only ,prefix)))) + bmkp-bmenu-title "Autofile Bookmarks") + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) "Only autofile bookmarks are shown"))) + +;;;###autoload (autoload 'bmkp-bmenu-show-only-file-bookmarks "bookmark+") +(defun bmkp-bmenu-show-only-file-bookmarks (&optional arg) ; Bound to `F S' in bookmark list + "Display a list of file and directory bookmarks (only). +With a prefix argument, do not include remote files or directories." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-bmenu-filter-function (if arg 'bmkp-local-file-alist-only 'bmkp-file-alist-only) + bmkp-bmenu-title (if arg + "Local File and Directory Bookmarks" + "File and Directory Bookmarks")) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) "Only file bookmarks are shown"))) + +;;;###autoload (autoload 'bmkp-bmenu-show-only-orphaned-local-file-bookmarks "bookmark+") +(defun bmkp-bmenu-show-only-orphaned-local-file-bookmarks (&optional arg) ; `O S' in bookmark list + "Display a list of orphaned local file and directory bookmarks (only). +With a prefix argument, include remote orphans as well." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-bmenu-filter-function (if arg + 'bmkp-orphaned-file-alist-only + 'bmkp-orphaned-local-file-alist-only) + bmkp-bmenu-title (if arg + "Orphaned File and Directory Bookmarks" + "Local Orphaned File and Directory Bookmarks")) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) "Only orphaned file bookmarks are shown"))) + +;;;###autoload (autoload 'bmkp-bmenu-show-only-specific-buffer-bookmarks "bookmark+") +(defun bmkp-bmenu-show-only-specific-buffer-bookmarks (&optional buffer) ; `= b S' in bookmark list + "Display (only) the bookmarks for BUFFER. +Interactively, read the BUFFER name. +If BUFFER is non-nil, set `bmkp-last-specific-buffer' to it." + (interactive (list (bmkp-completing-read-buffer-name))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when buffer (setq bmkp-last-specific-buffer buffer)) + (setq bmkp-bmenu-filter-function 'bmkp-last-specific-buffer-alist-only + bmkp-bmenu-title (format "Buffer `%s' Bookmarks" bmkp-last-specific-buffer)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) + (format "Only bookmarks for buffer `%s' are shown" + bmkp-last-specific-buffer)))) + +;;;###autoload (autoload 'bmkp-bmenu-show-only-specific-file-bookmarks "bookmark+") +(defun bmkp-bmenu-show-only-specific-file-bookmarks (&optional file) ; Bound to `= f S' in bookmark list + "Display (only) the bookmarks for FILE, an absolute file name. +Interactively, read the FILE name. +If FILE is non-nil, set `bmkp-last-specific-file' to it." + (interactive (list (bmkp-completing-read-file-name))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((orig-last-spec-file bmkp-last-specific-file) + (orig-filter-fn bmkp-bmenu-filter-function) + (orig-title bmkp-bmenu-title) + (orig-latest-alist bmkp-latest-bookmark-alist)) + (condition-case err + (progn + (when file (setq bmkp-last-specific-file file)) + (setq bmkp-bmenu-filter-function 'bmkp-last-specific-file-alist-only + bmkp-bmenu-title (format "File `%s' Bookmarks" bmkp-last-specific-file)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function)) + (bmkp-bmenu-state-file nil)) ; Prevent restoring saved state. + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) + (format "Only bookmarks for file `%s' are shown" + bmkp-last-specific-file))) + (raise-frame)) + (error (progn (setq bmkp-last-specific-file orig-last-spec-file + bmkp-bmenu-filter-function orig-filter-fn + bmkp-bmenu-title orig-title + bmkp-latest-bookmark-alist orig-latest-alist) + (error "%s" (error-message-string err))))))) + + +;;;###autoload (autoload 'bmkp-bmenu-refresh-menu-list "bookmark+") +(defun bmkp-bmenu-refresh-menu-list (&optional parg msg-p) ; Bound to `g' in bookmark list + "Refresh (revert) the bookmark list display (aka \"menu list\"). +This brings the displayed list up to date with respect to the current +bookmark list. It does not change the filtering or sorting of the +displayed list. + +With a prefix argument and upon confirmation, refresh the bookmark +list and its display from the current bookmark file. IOW, it reloads +the file, overwriting the current bookmark list. This also removes +any markings and omissions. + +You can use command `bmkp-toggle-bookmark-set-refreshes' to toggle +whether setting a bookmark in any way should automatically refresh the +list. + +From Lisp, non-nil optional arg MSG-P means show progress messages." + (interactive "P\np") + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((msg "Refreshing from bookmark ")) + (cond ((and parg (yes-or-no-p (format "Refresh list to bookmarks saved in file `%s'? " + bmkp-current-bookmark-file))) + (when msg-p (message (setq msg (concat msg "file...")))) + (bookmark-load bmkp-current-bookmark-file 'OVERWRITE 'BATCH-NO-SAVE) + (setq bmkp-bmenu-marked-bookmarks () ; Start from scratch. + bmkp-modified-bookmarks () + bmkp-flagged-bookmarks () + bmkp-bmenu-omitted-bookmarks (condition-case nil + (eval (car (get 'bmkp-bmenu-omitted-bookmarks + 'saved-value))) + (error nil))) + (let ((bmkp-bmenu-filter-function nil)) ; Remove any filtering. + (bmkp-refresh-menu-list (bookmark-bmenu-bookmark) (not msg-p)))) + (t + (when msg-p (message (setq msg (concat msg "list in memory...")))) + (bmkp-refresh-menu-list (bookmark-bmenu-bookmark) (not msg-p)))) + (when msg-p (message (concat msg "done"))))) + +;;;###autoload (autoload 'bmkp-bmenu-filter-bookmark-name-incrementally "bookmark+") +(defun bmkp-bmenu-filter-bookmark-name-incrementally () ; Bound to `P B' in bookmark list + "Incrementally filter bookmarks by bookmark name using a regexp." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (unwind-protect + (progn (setq bmkp-bmenu-filter-timer + (run-with-idle-timer bmkp-incremental-filter-delay 'REPEAT + #'bmkp-bmenu-filter-alist-by-bookmark-name-regexp)) + (bmkp-bmenu-read-filter-input)) + (bmkp-bmenu-cancel-incremental-filtering))) + +(defun bmkp-bmenu-filter-alist-by-bookmark-name-regexp () + "Filter bookmarks by bookmark name, then refresh the bookmark list." + (setq bmkp-bmenu-filter-function 'bmkp-regexp-filtered-bookmark-name-alist-only + bmkp-bmenu-title (format "Bookmarks with Names Matching Regexp `%s'" + bmkp-bmenu-filter-pattern)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp))) + +;;;###autoload (autoload 'bmkp-bmenu-filter-file-name-incrementally "bookmark+") +(defun bmkp-bmenu-filter-file-name-incrementally () ; Bound to `P F' in bookmark list + "Incrementally filter bookmarks by file name using a regexp." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (unwind-protect + (progn (setq bmkp-bmenu-filter-timer + (run-with-idle-timer bmkp-incremental-filter-delay 'REPEAT + #'bmkp-bmenu-filter-alist-by-file-name-regexp)) + (bmkp-bmenu-read-filter-input)) + (bmkp-bmenu-cancel-incremental-filtering))) + +(defun bmkp-bmenu-filter-alist-by-file-name-regexp () + "Filter bookmarks by file name, then refresh the bookmark list." + (setq bmkp-bmenu-filter-function 'bmkp-regexp-filtered-file-name-alist-only + bmkp-bmenu-title (format "Bookmarks with File Names Matching Regexp `%s'" + bmkp-bmenu-filter-pattern)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp))) + +;;;###autoload (autoload 'bmkp-bmenu-filter-annotation-incrementally "bookmark+") +(defun bmkp-bmenu-filter-annotation-incrementally () ; Bound to `P A' in bookmark list + "Incrementally filter bookmarks by their annotations using a regexp." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (unwind-protect + (progn (setq bmkp-bmenu-filter-timer + (run-with-idle-timer bmkp-incremental-filter-delay 'REPEAT + #'bmkp-bmenu-filter-alist-by-annotation-regexp)) + (bmkp-bmenu-read-filter-input)) + (bmkp-bmenu-cancel-incremental-filtering))) + +(defun bmkp-bmenu-filter-alist-by-annotation-regexp () + "Filter bookmarks by annoation, then refresh the bookmark list." + (setq bmkp-bmenu-filter-function 'bmkp-regexp-filtered-annotation-alist-only + bmkp-bmenu-title (format "Bookmarks with Annotations Matching Regexp `%s'" + bmkp-bmenu-filter-pattern)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp))) + +;;;###autoload (autoload 'bmkp-bmenu-filter-tags-incrementally "bookmark+") +(defun bmkp-bmenu-filter-tags-incrementally () ; Bound to `P T' in bookmark list + "Incrementally filter bookmarks by tags using a regexp." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (unwind-protect + (progn (setq bmkp-bmenu-filter-timer + (run-with-idle-timer bmkp-incremental-filter-delay 'REPEAT + #'bmkp-bmenu-filter-alist-by-tags-regexp)) + (bmkp-bmenu-read-filter-input)) + (bmkp-bmenu-cancel-incremental-filtering))) + +(defun bmkp-bmenu-filter-alist-by-tags-regexp () + "Filter bookmarks by tags, then refresh the bookmark list." + (setq bmkp-bmenu-filter-function 'bmkp-regexp-filtered-tags-alist-only + bmkp-bmenu-title (format "Bookmarks with Tags Matching Regexp `%s'" + bmkp-bmenu-filter-pattern)) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp))) + +(defun bmkp-bmenu-read-filter-input () + "Read input and add it to `bmkp-bmenu-filter-pattern'." + (setq bmkp-bmenu-filter-pattern "") + (let ((curr-bmk (bookmark-bmenu-bookmark)) + (orig-title bmkp-bmenu-title) + (orig-filt-fn bmkp-bmenu-filter-function) + (orig-filt-pat bmkp-bmenu-filter-pattern)) + (when (eq 'QUIT + (let ((tmp-list ()) + (inhibit-quit t) + (prefix-command-echo-keystrokes-functions ()) ; 25+ See Emacs bug #44500. + char) + (catch 'bmkp-bmenu-read-filter-input + (while (condition-case nil + (setq char (read-char (concat "Pattern: " bmkp-bmenu-filter-pattern))) + ;; `read-char' raises an error for non-char event. + (error (throw 'bmkp-bmenu-read-filter-input nil))) + (unless (or (not (fboundp 'characterp)) (characterp char)) ; E.g. `M-x', `M-:' + (throw 'bmkp-bmenu-read-filter-input nil)) + (case char + ((?\e ?\r) (throw 'bmkp-bmenu-read-filter-input nil)) ; Break and exit. + (?\C-g (setq inhibit-quit nil) + (throw 'bmkp-bmenu-read-filter-input 'QUIT)) ; Quit. + (?\d (or (null tmp-list) ; No-op if no chars to delete. + (pop tmp-list) + t)) ; Delete last char of `bmkp-bmenu-filter-pattern'. + (t (push (text-char-description char) tmp-list))) ; Accumulate CHAR. + (setq bmkp-bmenu-filter-pattern (mapconcat #'identity (reverse tmp-list) "")))))) + (message "Restoring display prior to incremental filtering...") + (setq bmkp-bmenu-title orig-title + bmkp-bmenu-filter-function orig-filt-fn + bmkp-bmenu-filter-pattern orig-filt-pat) + (bookmark-bmenu-list 'FILTEREDP) + (bmkp-bmenu-goto-bookmark-named curr-bmk) + (message "Restoring display prior to incremental filtering...done")))) + +(defun bmkp-bmenu-cancel-incremental-filtering () + "Cancel timer used for incrementally filtering bookmarks." + (cancel-timer bmkp-bmenu-filter-timer) + (setq bmkp-bmenu-filter-timer nil)) + +;;;###autoload (autoload 'bmkp-bmenu-toggle-show-only-unmarked "bookmark+") +(defun bmkp-bmenu-toggle-show-only-unmarked () ; Bound to `<' in bookmark list + "Hide all marked bookmarks. Repeat to toggle, showing all." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + ;; Save display, to be sure `bmkp-bmenu-before-hide-marked-alist' is up-to-date. + (bmkp-save-menu-list-state) + (if (or (bmkp-some-marked-p bmkp-latest-bookmark-alist) + (bmkp-some-marked-p bmkp-bmenu-before-hide-marked-alist)) + (let ((bookmark-alist bmkp-latest-bookmark-alist) + status) + (if bmkp-bmenu-before-hide-marked-alist + (setq bookmark-alist bmkp-bmenu-before-hide-marked-alist + bmkp-bmenu-before-hide-marked-alist () + bmkp-latest-bookmark-alist bookmark-alist + status 'shown) + (setq bmkp-bmenu-before-hide-marked-alist bmkp-latest-bookmark-alist + bookmark-alist (bmkp-unmarked-bookmarks-only) + bmkp-latest-bookmark-alist bookmark-alist + status 'hidden)) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (cond ((eq status 'hidden) + (bookmark-bmenu-ensure-position) + (message "Marked bookmarks are now hidden")) + (t + (goto-char (point-min)) + (when (re-search-forward "^>" (point-max) t) (forward-line 0)) + (message "Marked bookmarks no longer hidden")))) + (message "No marked bookmarks to hide")) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window))) + +;;;###autoload (autoload 'bmkp-bmenu-toggle-show-only-marked "bookmark+") +(defun bmkp-bmenu-toggle-show-only-marked () ; Bound to `>' in bookmark list + "Hide all unmarked bookmarks. Repeat to toggle, showing all." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + ;; Save display, to be sure `bmkp-bmenu-before-hide-unmarked-alist' is up-to-date. + (bmkp-save-menu-list-state) + (if (or (bmkp-some-unmarked-p bmkp-latest-bookmark-alist) + (bmkp-some-unmarked-p bmkp-bmenu-before-hide-unmarked-alist)) + (let ((bookmark-alist bmkp-latest-bookmark-alist) + status) + (if bmkp-bmenu-before-hide-unmarked-alist + (setq bookmark-alist bmkp-bmenu-before-hide-unmarked-alist + bmkp-bmenu-before-hide-unmarked-alist () + bmkp-latest-bookmark-alist bookmark-alist + status 'shown) + (setq bmkp-bmenu-before-hide-unmarked-alist bmkp-latest-bookmark-alist + bookmark-alist (bmkp-marked-bookmarks-only) + bmkp-latest-bookmark-alist bookmark-alist + status 'hidden)) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (cond ((eq status 'hidden) + (bookmark-bmenu-ensure-position) + (message "Unmarked bookmarks are now hidden")) + (t + (goto-char (point-min)) + (when (re-search-forward "^>" (point-max) t) (forward-line 0)) + (message "Unmarked bookmarks no longer hidden")))) + (message "No unmarked bookmarks to hide")) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window))) + + +;;(@* "Menu-List (`*-bmenu-*') Commands Involving Marks") +;; *** Menu-List (`*-bmenu-*') Commands Involving Marks *** + +;;;###autoload (autoload 'bmkp-bmenu-mark-all "bookmark+") +(defun bmkp-bmenu-mark-all (&optional no-re-sort-p msg-p) ; Bound to `M-m' in bookmark list + "Mark all bookmarks, using mark `>'. +If any bookmark was unmarked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive "i\np") + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks))) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) (bookmark-bmenu-mark 'NO-RE-SORT-P) (setq count (1+ count)))) + (unless no-re-sort-p + ;; If some were unmarked before, and if sort order is `s >' then re-sort. + (when (and (/= nb-marked count) (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p (message "Marked: %d" count)))) + +;; This is similar to `dired-unmark-all-files'. +;;;###autoload (autoload 'bmkp-bmenu-unmark-all "bookmark+") +(defun bmkp-bmenu-unmark-all (mark &optional arg no-re-sort-p msg-p) ; Bound to `M-DEL', `U' in bmk list + "Remove a mark from each bookmark. +Hit the mark character (`>' or `D') to remove those marks, + or hit `RET' to remove all marks (both `>' and `D'). +With a prefix arg, you are queried to unmark each marked bookmark. +Use `\\[help-command]' during querying for help. + +If any bookmark was marked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* MARK is the mark character or a carriage-return character (`?\r'). +* Non-nil ARG (prefix arg) means query. +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive "cRemove marks (RET means all): \nP\ni\np") + (bmkp-bmenu-barf-if-not-in-menu-list) + (require 'dired-aux) + (let* ((count 0) + (some-marked-p bmkp-bmenu-marked-bookmarks) + (inhibit-read-only t) + (case-fold-search nil) + (query nil) + (string (format "\n%c" mark)) + (help-form "Type SPC or `y' to unmark one bookmark, DEL or `n' to skip to next, +`!' to unmark all remaining bookmarks with no more questions.")) + (save-excursion + (goto-char (point-min)) + (forward-line (if (eq mark ?\r) + bmkp-bmenu-header-lines + (1- bmkp-bmenu-header-lines))) ; Because STRING starts with a newline. + (while (and (not (eobp)) + (if (eq mark ?\r) + (re-search-forward dired-re-mark nil t) + (let ((case-fold-search t)) ; Treat `d' the same as `D'. + (search-forward string nil t)))) + (when (or (prog1 (not arg) (when msg-p (message "Updating bookmark-list display..."))) + (let ((bmk (bookmark-bmenu-bookmark))) + (and bmk (dired-query 'query "Unmark bookmark `%s'? " bmk)))) + (bookmark-bmenu-unmark nil 'NO-RE-SORT-P) (forward-line -1) + (setq count (1+ count))))) + (unless no-re-sort-p + ;; If some were marked before, and if sort order is `s >', then re-sort. + (when (and some-marked-p (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p (if (= 1 count) (message "1 mark removed") (message "%d marks removed" count))))) + +;;;###autoload (autoload 'bmkp-bmenu-regexp-mark "bookmark+") +(defun bmkp-bmenu-regexp-mark (regexp &optional no-re-sort-p msg-p) ; Bound to `% m' in bookmark list + "Mark bookmarks that match REGEXP. +The entire bookmark line is tested: bookmark name and possibly file name. +Note too that if file names are not shown currently then the bookmark +name is padded at the right with spaces. + +If any bookmark was unmarked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive (list (bmkp-read-regexp "Regexp: ") (prefix-numeric-value current-prefix-arg))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks))) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (and (not (eobp)) (re-search-forward regexp (point-max) t)) + (bookmark-bmenu-mark 'NO-RE-SORT-P) + (setq count (1+ count)))) + (unless no-re-sort-p + ;; If some were unmarked before, and if sort order is `s >', then re-sort. + (when (and (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p)) + (< nb-marked (length bmkp-bmenu-marked-bookmarks))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p (if (= 1 count) (message "1 bookmark matched") (message "%d bookmarks matched" count))))) + +;;;###autoload (autoload 'bmkp-bmenu-mark-autofile-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-autofile-bookmarks (&optional arg msgp) ; Bound to `A M' in bookmark list + "Mark autofile bookmarks: those whose names are the same as their files. +With a prefix arg you are prompted for a prefix that each bookmark +name must have." + (interactive "P\np") + (if (not arg) + (bmkp-bmenu-mark-bookmarks-satisfying #'bmkp-autofile-bookmark-p nil msgp) + (let ((prefix (read-string "Prefix for bookmark names: " nil nil ""))) + (bmkp-bmenu-mark-bookmarks-satisfying + #'(lambda (bb) (bmkp-autofile-bookmark-p bb prefix)) nil msgp)))) + +;;;###autoload (autoload 'bmkp-bmenu-mark-autonamed-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-autonamed-bookmarks (&optional msgp) ; Bound to `# M' in bookmark list + "Mark autonamed bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying #'bmkp-autonamed-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmark-file-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-bookmark-file-bookmarks (&optional msgp) ; Bound to `Y M' in bookmark list + "Mark bookmark-file bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-bookmark-file-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmark-list-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-bookmark-list-bookmarks (&optional msgp) ; Bound to `Z M' in bookmark list + "Mark bookmark-list bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-bookmark-list-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-desktop-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-desktop-bookmarks (&optional msgp) ; Bound to `K M' in bookmark list + "Mark desktop bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-desktop-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-dired-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-dired-bookmarks (&optional msgp) ; Bound to `M-d M-m' in bookmark list + "Mark Dired bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-dired-bookmark-p nil msgp)) + +(when (fboundp 'bmkp-eww-bookmark-p) ; Emacs 25+ + + ;; ;;;###autoload (autoload 'bmkp-bmenu-mark-eww-bookmarks "bookmark+") + (defun bmkp-bmenu-mark-eww-bookmarks (&optional msgp) ; Bound to `W E M' in bookmark list + "Mark EWW (URL) bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-eww-bookmark-p nil msgp)) + + ) + +;;;###autoload (autoload 'bmkp-bmenu-mark-file-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-file-bookmarks (&optional arg msgp) ; Bound to `F M' in bookmark list + "Mark file bookmarks. +With a prefix argument, do not mark remote files or directories." + (interactive "P\np") + (bmkp-bmenu-mark-bookmarks-satisfying + (if arg 'bmkp-local-file-bookmark-p 'bmkp-file-bookmark-p nil msgp))) + +;;;###autoload (autoload 'bmkp-bmenu-mark-function-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-function-bookmarks (&optional msgp) ; Bound to `Q M' in bookmark list + "Mark function bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying #'bmkp-function-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-gnus-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-gnus-bookmarks (&optional msgp) ; Bound to `G M' in bookmark list + "Mark Gnus bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-gnus-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-icicles-search-hits-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-icicles-search-hits-bookmarks (&optional msgp) ; Bound to `i M' in bookmark list + "Mark Icicles search-hit bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-icicles-search-hits-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-image-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-image-bookmarks (&optional msgp) ; Bound to `M-I M-M' in bookmark list + "Mark image-file bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-image-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-info-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-info-bookmarks (&optional msgp) ; Bound to `I M' in bookmark list + "Mark Info bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-info-bookmark-p nil msgp)) + +(when (featurep 'bookmark+-lit) + (defun bmkp-bmenu-mark-lighted-bookmarks (&optional msgp) ; Bound to `H M' in bookmark list + "Mark the highlighted bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-lighted-p nil msgp))) + +;;;###autoload (autoload 'bmkp-bmenu-mark-man-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-man-bookmarks (&optional msgp) ; Bound to `M M' in bookmark list + "Mark `man' page bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-man-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-non-file-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-non-file-bookmarks (&optional msgp) ; Bound to `B M' in bookmark list + "Mark non-file bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-non-file-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-non-invokable-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-non-invokable-bookmarks (&optional msgp) ; Bound to `N M' in bookmark list + "Mark non-invokable bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-non-invokable-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-orphaned-local-file-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-orphaned-local-file-bookmarks (&optional arg msgp) ; Bound to `O M' in bookmark list + "Mark orphaned local-file bookmarks (their recorded files are not readable). +With a prefix argument, mark also remote orphaned files or directories." + (interactive "P\np") + (bmkp-bmenu-mark-bookmarks-satisfying + (if arg 'bmkp-orphaned-file-bookmark-p 'bmkp-orphaned-local-file-bookmark-p nil msgp))) + +;;;###autoload (autoload 'bmkp-bmenu-mark-region-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-region-bookmarks (&optional msgp) ; Bound to `R M' in bookmark list + "Mark bookmarks that record a region." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-region-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-snippet-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-snippet-bookmarks (&optional msgp) ; Bound to `w M' in bookmark list + "Mark snippet bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-snippet-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-specific-buffer-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-specific-buffer-bookmarks (&optional buffer msgp) ; `= b M' in bookmark list + "Mark bookmarks for BUFFER. +Interactively, read the name of the buffer. +If BUFFER is non-nil, set `bmkp-last-specific-buffer' to it." + (interactive (list (bmkp-completing-read-buffer-name) t)) + (when buffer (setq bmkp-last-specific-buffer buffer)) + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-last-specific-buffer-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-specific-file-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-specific-file-bookmarks (&optional file msgp) ; Bound to `= f M' in bookmark list + "Mark bookmarks for FILE, an absolute file name. +Interactively, read the file name. +If FILE is non-nil, set `bmkp-last-specific-file' to it." + (interactive (list (bmkp-completing-read-file-name) t)) + (when file (setq bmkp-last-specific-file file)) + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-last-specific-file-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-temporary-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-temporary-bookmarks (&optional msgp) ; Bound to `X M' in bookmark list + "Mark temporary bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-temporary-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-variable-list-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-variable-list-bookmarks (&optional msgp) ; Bound to `V M' in bookmark list + "Mark variable-list bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-variable-list-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-url-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-url-bookmarks (&optional msgp) ; Bound to `M-u M-m' in bookmark list + "Mark URL bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-url-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-w3m-bookmarks "bookmark+") +(defun bmkp-bmenu-mark-w3m-bookmarks (&optional msgp) ; Bound to `W 3 M' in bookmark list + "Mark W3M (URL) bookmarks." + (interactive "p") + (bmkp-bmenu-mark-bookmarks-satisfying 'bmkp-w3m-bookmark-p nil msgp)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmarks-satisfying "bookmark+") +(defun bmkp-bmenu-mark-bookmarks-satisfying (pred &optional no-re-sort-p msg-p) ; Not bound + "Mark bookmarks that satisfy predicate PRED. +If you use this interactively, you are responsible for entering a +symbol that names a unnary predicate. The function you provide is not +checked - it is simply applied to each bookmark to test it. + +If any bookmark was unmarked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive "aPredicate: \ni\np") + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks)) + bmk) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) + (setq bmk (bookmark-bmenu-bookmark)) + (if (not (funcall pred bmk)) + (forward-line 1) + (bookmark-bmenu-mark 'NO-RE-SORT-P) + (setq count (1+ count))))) + (unless no-re-sort-p + ;; If some were unmarked before, and if sort order is `s >', then re-sort. + (when (and (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p)) + (< nb-marked (length bmkp-bmenu-marked-bookmarks))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p (if (= 1 count) (message "1 bookmark matched") (message "%d bookmarks matched" count))))) + +;;;###autoload (autoload 'bmkp-bmenu-toggle-marks "bookmark+") +(defun bmkp-bmenu-toggle-marks (&optional backup no-re-sort-p msg-p) ; Bound to `t' in bookmark list + "Toggle marks: Unmark all marked bookmarks; mark all unmarked bookmarks. +This affects only the `>' mark, not the `D' flag. + +Interactively or with nil optional arg NO-RE-SORT-P, if the current +sort order is marked first or last (`s >'), then re-sort. + +Non-interactively, non-nil optional arg MSG-P means display a status +message." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((marked-count 0) + (unmarked-count 0)) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (if (not (bmkp-some-marked-p bmkp-latest-bookmark-alist)) + (bmkp-bmenu-mark-all no-re-sort-p) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) + (cond ((bmkp-bookmark-name-member (bookmark-bmenu-bookmark) bmkp-bmenu-marked-bookmarks) + (bookmark-bmenu-unmark nil 'NO-RE-SORT-P) + (setq unmarked-count (1+ unmarked-count))) + (t + (bookmark-bmenu-mark 'NO-RE-SORT-P) + (setq marked-count (1+ marked-count))))))) + ;; If sort order is `s >' then re-sort. + (when (and (not no-re-sort-p) (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk)))) + (when msg-p (message "Marked: %d, unmarked: %d" marked-count unmarked-count)))) + +;;;###autoload (autoload 'bmkp-bmenu-toggle-marked-temporary/savable "bookmark+") +(defun bmkp-bmenu-toggle-marked-temporary/savable () ; Bound to `M-X' in bookmark list + "Toggle the temporary/savable status of each marked bookmark. +If none are marked, toggle status of the bookmark of the current line." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((o-str (and (not (bmkp-looking-at-p "^>")) (bookmark-bmenu-bookmark))) + (o-point (point)) + (count-temp 0) + (count-save 0) + bmk) + (message "Toggling temporary status of marked bookmarks...") + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (while (re-search-forward "^>" (point-max) t) + (bmkp-toggle-temporary-bookmark (setq bmk (bookmark-bmenu-bookmark))) + (if (bmkp-temporary-bookmark-p bmk) + (setq count-temp (1+ count-temp)) + (setq count-save (1+ count-save)))) + (cond ((and (<= count-temp 0) (<= count-save 0)) + (if o-str + (bmkp-bmenu-goto-bookmark-named o-str) + (goto-char o-point) + (beginning-of-line)) + (bmkp-toggle-temporary-bookmark (bookmark-bmenu-bookmark) 'MSG) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P)) + (t + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (message "%d made temporary; %d made savable" count-temp count-save))) + (if o-str + (bmkp-bmenu-goto-bookmark-named o-str) + (goto-char o-point) + (beginning-of-line))) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window))) + +;;;###autoload (autoload 'bmkp-bmenu-toggle-temporary "bookmark+") +(defun bmkp-bmenu-toggle-temporary () ; Bound to `C-M-X' in bookmark list + "Toggle whether bookmark of current line is temporary (not saved to disk)." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((o-str (bookmark-bmenu-bookmark)) + (o-point (point))) + (bmkp-toggle-temporary-bookmark (bookmark-bmenu-bookmark) 'MSG) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (if o-str + (bmkp-bmenu-goto-bookmark-named o-str) + (goto-char o-point) + (beginning-of-line)))) + +;;;###autoload (autoload 'bmkp-bmenu-dired-marked "bookmark+") +(defun bmkp-bmenu-dired-marked (dirbufname &optional include-omitted-p) + ; Bound to `M-d >' in bookmark list + "Dired in another window for the marked file and directory bookmarks. +Absolute file names are used for the entries in the Dired buffer. +The only entries are for the marked files and directories. These can +be located anywhere. (In Emacs versions prior to release 23.2, remote +bookmarks are ignored, because of Emacs bug #5478.) + +You are prompted for the Dired buffer name. The `default-directory' +of the buffer is the same as that of buffer `*Bookmark List*'. + +Omitted bookmarks are excluded, by default. With a prefix arg, any +that are marked are included." + (interactive (list (read-string "Dired buffer name: ") current-prefix-arg)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((files ()) + file) + (dolist (bmk (bmkp-sort-omit (bmkp-bmenu-marked-or-this-or-all nil include-omitted-p))) + (when (or (bmkp-local-file-bookmark-p bmk) + (> emacs-major-version 23) + (and (= emacs-major-version 23) (> emacs-minor-version 1))) + (setq file (bookmark-get-filename bmk)) + (unless (file-name-absolute-p file) (setq file (expand-file-name file))) ; Should not happen. + (push file files))) + (dired-other-window (cons dirbufname files)))) + +;;;###autoload (autoload 'bmkp-bmenu-delete-marked "bookmark+") +(defun bmkp-bmenu-delete-marked (&optional no-confirm-p) ; Bound to `D' in bookmark list + "Delete all (visible) bookmarks that are marked `>', after confirmation. +Optional arg NO-CONFIRM-P non-nil means do not ask for confirmation." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-execute-deletions 'MARKED 'NO-CONFIRM)) + +;;;###autoload (autoload 'bmkp-bmenu-move-marked-to-bookmark-file "bookmark+") +(defun bmkp-bmenu-move-marked-to-bookmark-file (file &optional duplicates-ok include-omitted-p batchp) + ; Bound to `Y > -' in bookmark list + "Move the marked bookmarks to bookmark file FILE. +You are prompted for FILE. +The marked bookmarks are removed from the current bookmark list and +appended to those in FILE. If any of them has the same name as a +bookmark already in FILE then it is renamed by appending a numeric +suffix \"\" (N=2,3...). + +Normally, any of the marked bookmarks that are already present in FILE +are ignored, rather than duplicating them under a new, suffixed name. +But if you use a non-negative prefix arg then such duplication is +allowed. + +If no bookmark is marked then move the bookmark of the current line. + +Omitted bookmarks are excluded, by default. With a non-positive +prefix arg, any that are marked are included. + +The bookmarks are removed from the currently displayed bookmark list, +but the bookmark file associated with it is not saved automatically. +To save it, use \\`\\[bookmark-bmenu-save]' (as usual). + +Non-interactively, non-nil optional arg BATCHP means do not prompt to +confirm moving to new, empty file if no existing file." + (interactive + (list (let* ((_IGNORE (bmkp-bmenu-barf-if-not-in-menu-list)) + (std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + (and (not (bmkp-same-file-p bmkp-current-bookmark-file + bookmark-default-file)) + bookmark-default-file) + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Move marked bookmarks to bookmark file: " + (or (and default (file-name-directory default)) "~/") + default)) + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (<= (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when (and (not (file-readable-p file)) + (not batchp) + (not (y-or-n-p (format "Move to NEW, EMPTY bookmark file `%s'? " file)))) + (error "OK - canceled")) + (bmkp-bmenu-copy-marked-to-bookmark-file file duplicates-ok include-omitted-p 'MOVE 'BATCH)) + +;;;###autoload (autoload 'bmkp-bmenu-copy-marked-to-bookmark-file "bookmark+") +(defun bmkp-bmenu-copy-marked-to-bookmark-file (file &optional duplicates-ok include-omitted-p movep batchp) + ; Bound to `Y > +' in bookmark list + "Copy the marked bookmarks to bookmark file FILE. +You are prompted for FILE. +The marked bookmarks are appended to those already in FILE. +If any of them has the same name as a bookmark already in FILE then it +is renamed by appending a numeric suffix \"\" (N=2,3...). + +Normally, any of the marked bookmarks that are already present in FILE +are ignored, rather than duplicating them under a new, suffixed name. +But if you use a non-negative prefix arg then such duplication is +allowed. Use this, for example, to duplicate a bookmark in the +current bookmark file (use that file as FILE). + +If no bookmark is marked then copy the bookmark of the current line. + +Omitted bookmarks are excluded, by default. With a non-positive +prefix arg, any that are marked are included. + +Non-interactively: +* Non-nil MOVEP means delete the bookmarks copied. +* Non-nil BATCHP means do not prompt to confirm moving to a new, empty + file if there is no existing file." + (interactive + (list (let* ((_IGNORE (bmkp-bmenu-barf-if-not-in-menu-list)) + (std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + (and (not (bmkp-same-file-p bmkp-current-bookmark-file + bookmark-default-file)) + bookmark-default-file) + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Copy marked bookmarks to bookmark file: " + (or (and default (file-name-directory default)) "~/") + default)) + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (<= (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when (file-directory-p file) (error "`%s' is a directory, not a file" file)) + (when (and (not (file-readable-p file)) + (not batchp) + (not (y-or-n-p (format "Copy to NEW, EMPTY bookmark file `%s'? " file)))) + (error "OK - canceled")) + (let ((bookmark-save-flag nil) ; Inhibit auto-saving for the duration. + imported) + (let ((marked-bmks (bmkp-sort-omit + (bmkp-bmenu-marked-or-this-or-all nil include-omitted-p))) + (bookmark-alist bookmark-alist) + (bookmark-alist-modification-count bookmark-alist-modification-count)) + (when (and (not (zerop bookmark-alist-modification-count)) ; Unsaved changes. + (yes-or-no-p "Unsaved changes. Save bookmarks before copying? ")) + (bookmark-save)) + (with-current-buffer (let ((enable-local-variables ())) (find-file-noselect file)) + (goto-char (point-min)) + (if (file-exists-p file) + (bookmark-maybe-upgrade-file-format) + (delete-region (point-min) (point-max)) ; In case a find-file hook inserted a header etc. + (if (boundp 'bookmark-file-coding-system) ; Insert timestamp and an empty bookmark list. + (bookmark-insert-file-format-version-stamp bookmark-file-coding-system) ; Emacs 25.2+ + (bookmark-insert-file-format-version-stamp)) + (insert "(\n)")) + (let ((blist (bookmark-alist-from-buffer))) + (unless (listp blist) (error "Invalid bookmark list in file `%s'" file)) + (setq bookmark-alist blist) ; Bookmarks in FILE + (setq imported (bookmark-import-new-list marked-bmks duplicates-ok 'RETURN-BMKS)) + (if (and (zerop (nth 0 imported)) (zerop (nth 1 imported))) + (unless batchp (message "No changes")) + (unless batchp (message "%d added, %d renamed" (nth 1 imported) (nth 0 imported))) + (bookmark-write-file file))))) + ;; (Exit `let', to restore `bookmark-alist'.) + (cond (movep + ;; Moved. Delete moved bookmarks. Refresh from memory w/o asking. + (dolist (bmk (nth 2 imported)) (bookmark-delete bmk 'BATCHP)) + (bmkp-bmenu-refresh-menu-list nil 'MSGP)) + ((not (zerop (nth 0 imported))) + ;; Copied, and some were renamed. Refresh from file w/o asking. + (bookmark-load bmkp-current-bookmark-file 'OVERWRITE 'BATCH-NO-SAVE) + (bmkp-refresh-menu-list (bookmark-bmenu-bookmark)))))) + +;;;###autoload (autoload 'bmkp-bmenu-create-bookmark-file-from-marked "bookmark+") +(defun bmkp-bmenu-create-bookmark-file-from-marked (file create-b-f-bookmark-p + &optional include-omitted-p batchp) + ; Bound to `Y > 0' in bookmark list + "Create bookmark file FILE by copying the marked bookmarks. +You are prompted for FILE. +They are not deleted from the current bookmark file. To delete them, use \ +\\`\\[bmkp-bmenu-delete-marked]'. + +With a non-negative prefix arg, create also a bookmark-file bookmark +for FILE. You are prompted for the bookmark name. + +If no bookmark is marked then copy the bookmark of the current line. + +Omitted bookmarks are excluded, by default. With a non-positive +prefix arg, any that are marked are included. + +Non-interactively, non-nil optional arg BATCHP means do not prompt to +confirm moving to new, empty file if no existing file." + (interactive + (list (let* ((_IGNORE (bmkp-bmenu-barf-if-not-in-menu-list)) + (std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + (and (not (bmkp-same-file-p bmkp-current-bookmark-file + bookmark-default-file)) + bookmark-default-file) + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Create bookmark file from marked: " + (or (and default (file-name-directory default)) "~/") + default)) + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (<= (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when (and (file-readable-p file) + (not (file-directory-p file)) + (not batchp) + (not (y-or-n-p (format "File `%s' already exists. Overwrite? " file)))) + (error "OK - canceled")) + (bmkp-empty-file file) + (bmkp-bmenu-copy-marked-to-bookmark-file file nil include-omitted-p nil 'BATCH) + (when create-b-f-bookmark-p (bmkp-set-bookmark-file-bookmark file))) + +;;;###autoload (autoload 'bmkp-bmenu-set-bookmark-file-bookmark-from-marked "bookmark+") +(defun bmkp-bmenu-set-bookmark-file-bookmark-from-marked (file &optional include-omitted-p batchp) + ; Same as `C-u Y > 0' in bookmark list (but not bound). + "Set a bookmark-file bookmark for the marked bookmarks. +You are prompted for the names of the new bookmark file and the +bookmark-file bookmark. + +This is the same as using a non-negative prefix arg with +`bmkp-bmenu-create-bookmark-file-from-marked'. + +If no bookmark is marked then use the bookmark of the current line. + +Omitted bookmarks are excluded, by default. With a prefix arg, any +that are marked are included. + +Non-interactively, non-nil optional arg BATCHP means do not prompt to +confirm moving to new, empty file if no existing file." + (interactive + (list (let* ((_IGNORE (bmkp-bmenu-barf-if-not-in-menu-list)) + (std-default (bmkp-default-bookmark-file)) + (default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (if (bmkp-same-file-p bmkp-current-bookmark-file std-default) + (and (not (bmkp-same-file-p bmkp-current-bookmark-file + bookmark-default-file)) + bookmark-default-file) + std-default) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Create a bookmark file from marked: " + (or (and default (file-name-directory default)) "~/") + default)) + current-prefix-arg)) + (bmkp-bmenu-create-bookmark-file-from-marked file 'CREATE-B-F-BMK include-omitted-p batchp)) + +;;;###autoload (autoload 'bmkp-bmenu-load-marked-bookmark-file-bookmarks "bookmark+") +(defun bmkp-bmenu-load-marked-bookmark-file-bookmarks (&optional msg-p) ; Bound to `M-l' in bookmark list + "Load the bookmark-file bookmarks that are marked, in display order. +Non bookmark-file bookmarks that are marked are ignored. +You can sort the bookmark-list display to change the load order. + +NOTE: Automatically saving the current bookmark list is turned OFF +before loading, and it remains turned off until you explicitly turn it +back on. Bookmark+ does not assume that you want to automatically +save all of the newly loaded bookmarks in the same bookmark file. If +you do, just use \\`\\[bmkp-toggle-saving-bookmark-file]' \ +to turn saving back on." + (interactive "p") + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((bmks (bmkp-remove-if-not #'bmkp-bookmark-file-bookmark-p + (bmkp-remove-if-not 'bmkp-marked-bookmark-p bmkp-sorted-alist))) + (bmk (bookmark-bmenu-bookmark))) + (unless bmks (error "No marked bookmark-file bookmarks")) + ;; Maybe save bookmarks first. + (when (or (not msg-p) + (and (> bookmark-alist-modification-count 0) + (condition-case err + (yes-or-no-p "Save current bookmarks? (`C-g': cancel load too) ") + (quit (error "OK - canceled")) + (error (error (error-message-string err)))))) + (bookmark-save)) + (when (or (not msg-p) + (yes-or-no-p "Load the marked bookmark-file bookmarks? ") + (error "OK - canceled")) + (when bookmark-save-flag ; Turn off autosaving. + (bmkp-toggle-saving-bookmark-file) ; No MSG-P arg - issue message below. + (when bookmark-save-flag (setq bookmark-save-flag nil)) ; Be sure it's off. + (when msg-p (message "Autosaving of current bookmark file is now OFF"))) + (when msg-p (message "Loading marked bookmark files...")) + (dolist (bmk bmks) ; Load. + ;; USE BATCHP: Do not refresh list or display messages here - do that after iterate. + (bookmark-load (bookmark-get-filename bmk) nil 'BATCHP)) + ;; $$$$$$ Should we do (bmkp-tags-list) here to update the tags cache? + (bmkp-refresh-menu-list bmk (not msg-p)) ; Refresh after iterate. + (when msg-p (message "Autosaving is now OFF. Loaded: %s" + (mapconcat (lambda (bmk) (format "`%s'" (bmkp-bookmark-name-from-record bmk))) + bmks + ", ")))))) + +;;;###autoload (autoload 'bmkp-bmenu-load-marking "bookmark+") +(defun bmkp-bmenu-load-marking (file &optional unmark-first-p) + "Like `bookmark-load', but mark the bookmarks that are loaded. +With a prefix arg, unmark all bookmarks first." + (interactive + (list (let ((default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (bmkp-default-bookmark-file) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Add bookmarks from file: " + (or (file-name-directory default) "~/") + default + t)) + current-prefix-arg)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when unmark-first-p (bmkp-bmenu-unmark-all ?\r)) + (let* ((bmkp-read-bookmark-file-hook bmkp-read-bookmark-file-hook) + (bmks-read (bookmark-load file))) + (bmkp-bmenu-mark-bookmarks-satisfying + `(lambda (bmk) (bmkp-get-bookmark-in-alist bmk t ',bmks-read))) + bmks-read)) ; Return list of bookmarks read. + +;;;###autoload (autoload 'bmkp-bmenu-load-marking-unmark-first "bookmark+") +(defun bmkp-bmenu-load-marking-unmark-first (file) + "Like `bmkp-bmenu-load-marking' with a prefix arg: unmark all first." + (interactive + (list (let ((default (if (bmkp-same-file-p bmkp-current-bookmark-file bmkp-last-bookmark-file) + (bmkp-default-bookmark-file) + bmkp-last-bookmark-file))) + (bmkp-read-bookmark-file-name "Add bookmarks from file: " + (or (file-name-directory default) "~/") + default + t)))) + (bmkp-bmenu-load-marking file t)) + +;;;###autoload (autoload 'bmkp-bmenu-make-sequence-from-marked "bookmark+") +(defun bmkp-bmenu-make-sequence-from-marked (seqname &optional dont-omit-p) ; Not bound + "Create or update a sequence bookmark from the visible marked bookmarks. +The bookmarks that are currently marked are recorded as a sequence, in +their current order in buffer `*Bookmark List*'. +When you \"jump\" to the sequence bookmark, the bookmarks in the +sequence are processed in order. + +By default, omit the marked bookmarks, after creating the sequence. +With a prefix arg, do not omit them. + +If a bookmark with the specified name already exists, it is +overwritten. If a sequence bookmark with the name already exists, +then you are prompted whether to add the marked bookmarks to the +beginning of the existing sequence (or simply replace it). + +Note that another existing sequence bookmark can be marked, and thus +included in the sequence bookmark created or updated. That is, you +can include other sequences within a sequence bookmark. + +Returns the bookmark (internal record) created or updated." + (interactive "sName of sequence bookmark: \nP") + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((marked-bmks ()) + (count 0)) + (message "Making sequence from marked bookmarks...") + (save-excursion (with-current-buffer bmkp-bmenu-buffer + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (while (re-search-forward "^>" (point-max) t) + (push (bookmark-bmenu-bookmark) marked-bmks) + (setq count (1+ count))))) + (when (zerop count) (error "No marked bookmarks")) + (bmkp-set-sequence-bookmark seqname (nreverse marked-bmks))) + (let ((new (bmkp-get-bookmark seqname 'NOERROR))) + (unless (memq new bmkp-latest-bookmark-alist) + (setq bmkp-latest-bookmark-alist (cons new bmkp-latest-bookmark-alist))) + (unless dont-omit-p + (bmkp-bmenu-omit-marked) + (message (substitute-command-keys "Marked bookmarks now OMITTED - use \ +\\`\\[bmkp-bmenu-show-only-omitted-bookmarks]' to show"))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (bmkp-bmenu-goto-bookmark-named seqname) + new)) + + +;;(@* "Omitted Bookmarks") +;; *** Omitted Bookmarks *** + +;;;###autoload (autoload 'bmkp-bmenu-omit "bookmark+") +(defun bmkp-bmenu-omit () ; Not bound + "Omit this bookmark." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (push (bookmark-bmenu-bookmark) bmkp-bmenu-omitted-bookmarks) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (message "Omitted 1 bookmark")) + +;;;###autoload (autoload 'bmkp-bmenu-omit/unomit-marked "bookmark+") +(defun bmkp-bmenu-omit/unomit-marked () ; Bound to `- >' in bookmark list + "Omit all marked bookmarks or, if showing only omitted ones, unomit." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (if (eq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only) + (bmkp-bmenu-unomit-marked) + (bmkp-bmenu-omit-marked))) + +;;;###autoload (autoload 'bmkp-bmenu-omit-marked "bookmark+") +(defun bmkp-bmenu-omit-marked () ; Bound to `- >' in bookmark list + "Omit all marked bookmarks. +They will henceforth be invisible to the bookmark list. +You can, however, use \\`\\[bmkp-bmenu-show-only-omitted-bookmarks]' \ +to see them. +You can then mark some of them and use `\\[bmkp-bmenu-omit/unomit-marked]' to make those marked + available again for the bookmark list." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((o-str (and (not (bmkp-looking-at-p "^>")) (bookmark-bmenu-bookmark))) + (o-point (point)) + (count 0)) + (message "Omitting marked bookmarks...") + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (while (re-search-forward "^>" (point-max) t) + (setq bmkp-bmenu-omitted-bookmarks (cons (bookmark-bmenu-bookmark) bmkp-bmenu-omitted-bookmarks) + count (1+ count))) + (if (<= count 0) + (message "No marked bookmarks") + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (message "Omitted %d bookmarks" count)) + (if o-str + (bmkp-bmenu-goto-bookmark-named o-str) + (goto-char o-point) + (beginning-of-line))) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window))) + +;;;###autoload (autoload 'bmkp-bmenu-unomit-marked "bookmark+") +(defun bmkp-bmenu-unomit-marked () ; `- >' in bookmark list when showing omitted bookmarks + "Remove all marked bookmarks from the list of omitted bookmarks. +They will henceforth be available for display in the bookmark list. +\(In order to see and then mark omitted bookmarks you must use \\\ +`\\[bmkp-bmenu-show-only-omitted-bookmarks]'.)" + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (unless bmkp-bmenu-omitted-bookmarks (error "No omitted bookmarks to UN-omit")) + (unless (eq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only) + (error "You must use command `bmkp-bmenu-show-only-omitted-bookmarks' first")) + (let ((count 0)) + (message "UN-omitting marked bookmarks...") + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (while (re-search-forward "^>" (point-max) t) + (let ((bmk-name (bookmark-bmenu-bookmark))) + (when (bmkp-bookmark-name-member bmk-name bmkp-bmenu-omitted-bookmarks) + (setq bmkp-bmenu-omitted-bookmarks (bmkp-delete-bookmark-name-from-list + bmk-name bmkp-bmenu-omitted-bookmarks) + count (1+ count))))) + (if (<= count 0) + (message "No marked bookmarks") + (setq bmkp-bmenu-filter-function nil + bmkp-bmenu-title "All Bookmarks" + bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (message "UN-omitted %d bookmarks" count))) + (when (and (fboundp 'fit-frame-if-one-window) + (eq (selected-window) (get-buffer-window (get-buffer-create bmkp-bmenu-buffer) 0))) + (fit-frame-if-one-window))) + +;;;###autoload (autoload 'bmkp-bmenu-show-only-omitted-bookmarks "bookmark+") +(defun bmkp-bmenu-show-only-omitted-bookmarks () ; Bound to `- S' in bookmark list to show only omitted + "Show only the omitted bookmarks. +You can then mark some of them and use `\\\\[bmkp-bmenu-omit/unomit-marked]' to + make those that are marked available again for the bookmark list." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (unless bmkp-bmenu-omitted-bookmarks (error "No omitted bookmarks")) ; Cannot use macro for this. + (setq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only + bmkp-bmenu-title "Omitted Bookmarks") + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) "Only omitted bookmarks are shown now"))) + + +;;(@* "Search-and-Replace Locations of Marked Bookmarks") +;; *** Search-and-Replace Locations of Marked Bookmarks *** + +(when (> emacs-major-version 22) + (defun bmkp-bmenu-isearch-marked-bookmarks (&optional allp include-omitted-p) + ; Bound to `M-s a C-s' in bookmark list + "Isearch the marked bookmark locations, in their current order. +If no bookmark is marked, search the bookmark of the current line. + +With a non-negative prefix arg, search all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((bookmarks (mapcar #'car (bmkp-sort-omit + (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p)))) + (bmkp-use-region nil)) ; Suppress region handling. + (bmkp-isearch-bookmarks bookmarks))) ; Defined in `bookmark+-1.el'. + + (defun bmkp-bmenu-isearch-marked-bookmarks-regexp (&optional allp include-omitted-p) + ; `M-s a M-C-s' in bookmark list + "Regexp Isearch the marked bookmark locations, in their current order. +If no bookmark is marked, search the bookmark of the current line. + +With a non-negative prefix arg, search all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((bookmarks (mapcar #'car (bmkp-sort-omit + (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p)))) + (bmkp-use-region nil)) ; Suppress region handling. + (bmkp-isearch-bookmarks-regexp bookmarks)))) ; Defined in `bookmark+-1.el'. + +;;;###autoload (autoload 'bmkp-bmenu-search-marked-bookmarks-regexp "bookmark+") +(defun bmkp-bmenu-search-marked-bookmarks-regexp (regexp &optional allp include-omitted-p) + ; `M-s a M-s' in bookmark list + "Search the marked file bookmarks, in their current order, for REGEXP. +Use `\\[tags-loop-continue]' to advance among the search hits. +Marked directory and non-file bookmarks are ignored. + +If no bookmark is marked, search the bookmark of the current line. + +With a non-negative prefix arg, search all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included." + (interactive (list (bmkp-read-regexp "Search marked file bookmarks (regexp): ") + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (tags-search regexp '(let ((files ()) + file) + (dolist (bmk (bmkp-sort-omit + (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p))) + (setq file (bookmark-get-filename bmk)) + (when (and (not (equal bmkp-non-file-filename file)) + (not (file-directory-p file))) + (push file files))) + (setq files (nreverse files))))) + +;;;###autoload (autoload 'bmkp-bmenu-query-replace-marked-bookmarks-regexp "bookmark+") +(defun bmkp-bmenu-query-replace-marked-bookmarks-regexp (from to ; Bound to `M-q' in bookmark list + &optional delimited include-omitted-p) + "`query-replace-regexp' FROM with TO, for all marked file bookmarks. +If you exit (`\\[keyboard-quit]', `RET' or `q'), you can use `\\[tags-loop-continue]' to resume where +you left off. + +If no bookmark is marked, act on the bookmark of the current line. + +A non-negative prefix arg means replace only word-delimited matches. + +Omitted bookmarks are excluded, by default. With a non-positive +prefix arg, any that are marked are included." + (interactive (let ((common (query-replace-read-args "Query replace regexp in marked files" t t))) + (list (nth 0 common) + (nth 1 common) + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (<= (prefix-numeric-value current-prefix-arg) 0))))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (tags-query-replace from to delimited + '(let ((files ()) + file) + (dolist (bmk (bmkp-sort-omit + (bmkp-bmenu-marked-or-this-or-all nil include-omitted-p))) + (setq file (bookmark-get-filename bmk)) + (let ((buffer (get-file-buffer file))) + (when (and buffer (with-current-buffer buffer buffer-read-only)) + (error "File `%s' is visited read-only" file))) + (when (and (not (equal bmkp-non-file-filename file)) + (not (file-directory-p file))) + (push file files))) + (setq files (nreverse files))))) + + +;;(@* "Tags") +;; *** Tags *** + +;; Not bound, but `T 0' is `bmkp-remove-all-tags'. +;;;###autoload (autoload 'bmkp-bmenu-remove-all-tags "bookmark+") +(defun bmkp-bmenu-remove-all-tags (&optional must-confirm-p) + "Remove all tags from this bookmark. +Interactively, you are required to confirm." + (interactive "p") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bookmark (bookmark-bmenu-bookmark))) + (when (and must-confirm-p (null (bmkp-get-tags bookmark))) + (error "Bookmark has no tags to remove")) + (when (or (not must-confirm-p) (y-or-n-p "Remove all tags from this bookmark? ")) + (bmkp-remove-all-tags bookmark)))) + +;;;###autoload (autoload 'bmkp-bmenu-add-tags "bookmark+") +(defun bmkp-bmenu-add-tags () ; Only on `mouse-3' menu in bookmark list. + "Add some tags to this bookmark." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((nb-added (bmkp-add-tags (bookmark-bmenu-bookmark) (bmkp-read-tags-completing)))) + (when (and (< nb-added 0) ; It was untagged but is now tagged. If `s t' then re-sort. + (equal bmkp-sort-comparer '((bmkp-tagged-cp) bmkp-alpha-p))) ; Hardcoded value, for now. + (bmkp-bmenu-sort-tagged-before-untagged)) + nb-added)) + +;;;###autoload (autoload 'bmkp-bmenu-set-tag-value "bookmark+") +(defun bmkp-bmenu-set-tag-value () ; Bound to `T v' in bookmark list + "Set the value of one of this bookmark's tags." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((this-bmk (bookmark-bmenu-bookmark))) + (bmkp-set-tag-value + this-bmk + (bmkp-read-tag-completing "Tag: " (mapcar 'bmkp-full-tag (bmkp-get-tags this-bmk))) + (read (read-string "Value: ")) + nil + 'MSG))) + +;;;###autoload (autoload 'bmkp-bmenu-set-tag-value-for-marked "bookmark+") +(defun bmkp-bmenu-set-tag-value-for-marked (tag value &optional allp include-omitted-p msg-p) + ; Bound to `T > v' in bookmark list + "Set the value of TAG to VALUE, for each of the marked bookmarks. +If any of the bookmarks has no tag named TAG, then add one with VALUE. + +If no bookmark is marked, act on the bookmark of the current line. + +With a non-negative prefix arg, act on all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included. + +Non-interactively, non-nil MSG-P means display messages." + (interactive (list (bmkp-read-tag-completing) + (read (read-string "Value: ")) + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)) + 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when msg-p (message "Setting tag values...")) + (let ((marked (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p))) + (unless marked (error "No marked bookmarks")) + (when msg-p (message "Setting tag values...")) + (bmkp-set-tag-value-for-bookmarks marked tag value)) + (when (and msg-p tag) (message "Setting tag values...done"))) + +;;;###autoload (autoload 'bmkp-bmenu-remove-tags "bookmark+") +(defun bmkp-bmenu-remove-tags (&optional msg-p) ; Only on `mouse-3' menu in bookmark list. + "Remove some tags from this bookmark. +Non-interactively, non-nil MSG-P means display messages." + (interactive "p") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let* ((bmk (bookmark-bmenu-bookmark)) + (nb-removed (bmkp-remove-tags bmk + (bmkp-read-tags-completing + (mapcar 'bmkp-full-tag (bmkp-get-tags bmk)) t) + nil + msg-p))) + (when (and (< nb-removed 0) ; It was tagged but is now untagged. If `s t' then re-sort. + (equal bmkp-sort-comparer '((bmkp-tagged-cp) bmkp-alpha-p))) ; Hardcoded value, for now. + (bmkp-bmenu-sort-tagged-before-untagged)) + nb-removed)) + +;;;###autoload (autoload 'bmkp-bmenu-add-tags-to-marked "bookmark+") +(defun bmkp-bmenu-add-tags-to-marked (tags &optional allp include-omitted-p msg-p) + ; Bound to `T > +' in bookmark list + "Add TAGS to each of the marked bookmarks. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter each tag, but you are not limited to +choosing existing tags. + +If no bookmark is marked, act on the bookmark of the current line. + +With a non-negative prefix arg, act on all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included. + +Non-interactively: + TAGS is a list of strings. + Non-nil MSG-P means display messages." + (interactive (list (bmkp-read-tags-completing) + (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)) + 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((marked (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p)) + (curr-bmk (bookmark-bmenu-bookmark)) + (some-were-untagged-p nil)) + (unless marked (error "No marked bookmarks")) + (when msg-p (message "Adding tags...")) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk (mapcar #'car marked)) + (when (< (bmkp-add-tags bmk tags 'NO-UPDATE-P) 0) (setq some-were-untagged-p t)))) + (bmkp-tags-list) ; Update the tags cache now, after iterate. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh-menu-list curr-bmk (not msg-p)) ; Refresh after iterate. + (when (and some-were-untagged-p (equal bmkp-sort-comparer '((bmkp-tagged-cp) bmkp-alpha-p))) + (bmkp-bmenu-sort-tagged-before-untagged)) + (when (and msg-p tags) (message "Tags added: %S" tags)))) + +;;;###autoload (autoload 'bmkp-bmenu-remove-tags-from-marked "bookmark+") +(defun bmkp-bmenu-remove-tags-from-marked (tags &optional allp include-omitted-p msg-p) + ; Bound to `T > -' in bookmark list + "Remove TAGS from each of the marked bookmarks. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter each tag. + +If no bookmark is marked, act on the bookmark of the current line. + +With a non-negative prefix arg, act on all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included. + +Non-interactively, non-nil MSG-P means display messages." + (interactive + (let ((tgs ()) + (all (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0))) + (omt (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)))) + + (dolist (bmk (bmkp-bmenu-marked-or-this-or-all all omt)) + (setq tgs (bmkp-set-union tgs (bmkp-get-tags bmk)))) + (unless tgs (error "No tags to remove")) + (list (bmkp-read-tags-completing tgs t) all omt 'MSG))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((marked (if allp + bookmark-alist + (or (if include-omitted-p + (bmkp-marked-bookmarks-only) + (bmkp-remove-if #'bmkp-omitted-bookmark-p (bmkp-marked-bookmarks-only))) + (and (bookmark-bmenu-bookmark) + (list (bmkp-get-bookmark (bookmark-bmenu-bookmark))))))) + (curr-bmk (bookmark-bmenu-bookmark)) + (some-are-now-untagged-p nil)) + (unless marked (error "No marked bookmarks")) + (when msg-p (message "Removing tags...")) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk (mapcar #'car marked)) + (when (< (bmkp-remove-tags bmk tags 'NO-UPDATE-P) 0) (setq some-are-now-untagged-p t)))) + (bmkp-tags-list) ; Update the tags cache now, after iterate. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh-menu-list curr-bmk (not msg-p)) ; Refresh after iterate. + (when (and some-are-now-untagged-p (equal bmkp-sort-comparer '((bmkp-tagged-cp) bmkp-alpha-p))) + (bmkp-bmenu-sort-tagged-before-untagged)) + (when (and msg-p tags) (message "Tags removed: %S" tags)))) + +;;;###autoload (autoload 'bmkp-bmenu-list-tags-of-marked "bookmark+") +(defun bmkp-bmenu-list-tags-of-marked (fullp &optional msg-p) + ; Bound to `T > l' in bookmark list + "List the tags used in the marked bookmarks. +Show the list in the minibuffer or, if not enough space, in buffer +`*All Tags*'. The tags are listed alphabetically, respecting option +`case-fold-search'. + +With no prefix arg, list only the tag names. With a prefix arg, list +the full alist of tags. Note that when the full tags alist is shown, +the same tag name appears once for each of its different values. + +Non-interactively, non-nil MSG-P means display a status message." + (interactive "P\np") + (require 'pp) + (when msg-p (message "Gathering tags...")) + (pp-display-expression (sort (let ((bookmark-alist (bmkp-marked-bookmarks-only)) + bmkp-tags-alist) ; Prevent updating it. + (bmkp-tags-list (not fullp) t)) + (if fullp + (lambda (t1 t2) (bmkp-string-less-case-fold-p (car t1) (car t2))) + 'bmkp-string-less-case-fold-p)) + "*Tags of Marked Bookmarks*")) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmarks-tagged-regexp "bookmark+") +(defun bmkp-bmenu-mark-bookmarks-tagged-regexp (regexp &optional notp no-re-sort-p msg-p) + ; `T m %' in bookmark list + "Mark bookmarks any of whose tags match REGEXP. +With a prefix arg, mark all that are tagged but have no matching tags. + +If any bookmark was unmarked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil NOTP: see prefix arg, above. +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive (list (bmkp-read-regexp "Regexp: ") current-prefix-arg nil + (prefix-numeric-value current-prefix-arg))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks)) + tags anyp) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) + (setq tags (bmkp-get-tags (bookmark-bmenu-bookmark)) + anyp (and tags (bmkp-some (lambda (tag) (bmkp-string-match-p regexp (bmkp-tag-name tag))) + tags))) + (if (not (and tags (if notp (not anyp) anyp))) + (forward-line 1) + (bookmark-bmenu-mark 'NO-RE-SORT-P) + (setq count (1+ count))))) + (unless no-re-sort-p + ;; If some were unmarked before, and if sort order is `s >', then re-sort. + (when (and (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p)) + (/= nb-marked (length bmkp-bmenu-marked-bookmarks))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p (if (= 1 count) (message "1 bookmark matched") (message "%d bookmarks matched" count))))) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmarks-tagged-all "bookmark+") +(defun bmkp-bmenu-mark-bookmarks-tagged-all (tags &optional nonep msg-p) ; `T m *' in bookmark list + "Mark all visible bookmarks that are tagged with *each* tag in TAGS. +As a special case, if TAGS is empty, then mark the bookmarks that have +any tags at all (i.e., at least one tag). + +With a prefix arg, mark all that are *not* tagged with *any* TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-all/none tags nonep nil nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmarks-tagged-none "bookmark+") +(defun bmkp-bmenu-mark-bookmarks-tagged-none (tags &optional allp msg-p) ; `T m ~ +' in bookmark list + "Mark all visible bookmarks that are not tagged with *any* tag in TAGS. +As a special case, if TAGS is empty, then mark the bookmarks that have +no tags at all. + +With a prefix arg, mark all that are tagged with *each* tag in TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-all/none tags (not allp) nil nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmarks-tagged-some "bookmark+") +(defun bmkp-bmenu-mark-bookmarks-tagged-some (tags &optional somenotp msg-p) ; `T m +' in bookmark list + "Mark all visible bookmarks that are tagged with *some* tag in TAGS. +As a special case, if TAGS is empty, then mark the bookmarks that have +any tags at all. + +With a prefix arg, mark all that are *not* tagged with *all* TAGS. + +Hit `RET' to enter each tag, then hit `RET' again after the last tag. +You can use completion to enter each tag." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-some/not-all tags somenotp nil nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-mark-bookmarks-tagged-not-all "bookmark+") +(defun bmkp-bmenu-mark-bookmarks-tagged-not-all (tags &optional somep msg-p) ; `T m ~ *' in bmk list + "Mark all visible bookmarks that are *not* tagged with *all* TAGS. +As a special case, if TAGS is empty, then mark the bookmarks that have +no tags at all. + +With a prefix arg, mark all that are tagged with *some* tag in TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-some/not-all tags (not somep) nil nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-unmark-bookmarks-tagged-regexp "bookmark+") +(defun bmkp-bmenu-unmark-bookmarks-tagged-regexp (regexp &optional notp no-re-sort-p msg-p) + ; `T u %' in bookmark list + "Unmark bookmarks any of whose tags match REGEXP. +With a prefix arg, mark all that are tagged but have no matching tags. + +If any bookmark was marked before, and if the sort order is marked +first or last (`s >'), then re-sort. + +Non-interactively: +* Non-nil NOTP: see prefix arg, above. +* Non-nil optional arg NO-RE-SORT-P inhibits re-sorting. +* Non-nil optional arg MSG-P means display a status message." + (interactive (list (bmkp-read-regexp "Regexp: ") current-prefix-arg nil + (prefix-numeric-value current-prefix-arg))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks)) + tags anyp) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) + (setq tags (bmkp-get-tags (bookmark-bmenu-bookmark)) + anyp (and tags (bmkp-some (lambda (tag) (bmkp-string-match-p regexp (bmkp-tag-name tag))) + tags))) + (if (not (and tags (if notp (not anyp) anyp))) + (forward-line 1) + (bookmark-bmenu-unmark nil 'NO-RE-SORT-P) + (setq count (1+ count))))) + (unless no-re-sort-p + ;; If some were marked before, and if sort order is `s >', then re-sort. + (when (and (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p)) + (/= nb-marked (length bmkp-bmenu-marked-bookmarks))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p (if (= 1 count) (message "1 bookmark matched") (message "%d bookmarks matched" count))))) + +;;;###autoload (autoload 'bmkp-bmenu-unmark-bookmarks-tagged-all "bookmark+") +(defun bmkp-bmenu-unmark-bookmarks-tagged-all (tags &optional nonep msg-p) ; `T u *' in bookmark list + "Unmark all visible bookmarks that are tagged with *each* tag in TAGS. +As a special case, if TAGS is empty, then unmark the bookmarks that have +any tags at all. + +With a prefix arg, unmark all that are *not* tagged with *any* TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-all/none tags nonep 'UNMARK nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-unmark-bookmarks-tagged-none "bookmark+") +(defun bmkp-bmenu-unmark-bookmarks-tagged-none (tags &optional allp msg-p) ; `T u ~ +' in bookmark list + "Unmark all visible bookmarks that are *not* tagged with *any* TAGS. +As a special case, if TAGS is empty, then unmark the bookmarks that have +no tags at all. + +With a prefix arg, unmark all that are tagged with *each* tag in TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-all/none tags (not allp) 'UNMARK nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-unmark-bookmarks-tagged-some "bookmark+") +(defun bmkp-bmenu-unmark-bookmarks-tagged-some (tags &optional somenotp msg-p) ; `T u +' in bmk list + "Unmark all visible bookmarks that are tagged with *some* tag in TAGS. +As a special case, if TAGS is empty, then unmark the bookmarks that have +any tags at all. + +With a prefix arg, unmark all that are *not* tagged with *all* TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-some/not-all tags somenotp 'UNMARK nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-unmark-bookmarks-tagged-not-all "bookmark+") +(defun bmkp-bmenu-unmark-bookmarks-tagged-not-all (tags &optional somep msg-p) ; `T u ~ *' in bmk list + "Unmark all visible bookmarks that are *not* tagged with *all* TAGS. +As a special case, if TAGS is empty, then unmark the bookmarks that have +no tags at all. + +With a prefix arg, unmark all that are tagged with *some* TAGS." + (interactive (list (bmkp-read-tags-completing) current-prefix-arg 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-bmenu-mark/unmark-bookmarks-tagged-some/not-all tags (not somep) 'UNMARK nil msg-p)) + +(defun bmkp-bmenu-mark/unmark-bookmarks-tagged-all/none (tags &optional nonep unmarkp no-re-sort-p msg-p) + "Mark or unmark visible bookmarks tagged with all or none of TAGS. +TAGS is a list of strings, the tag names. +Non-nil NONEP means mark/unmark bookmarks that have none of the TAGS. +Non-nil UNMARKP means unmark; nil means mark. +Non-nil NO-RE-SORT-P inhibits re-sorting. +Non-nil MSG-P means display a status message. + +As a special case, if TAGS is empty, then mark or unmark the bookmarks +that have any tags at all, or if NONEP is non-nil then mark or unmark +those that have no tags at all. + +If any bookmark was (un)marked before but is not afterward, and if the +sort order is marked first or last (`s >'), then re-sort." + (with-current-buffer bmkp-bmenu-buffer + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks)) + bmktags presentp) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) + (setq bmktags (bmkp-get-tags (bookmark-bmenu-bookmark))) + (if (not (if (null tags) + (if nonep (not bmktags) bmktags) + (and bmktags (catch 'bmkp-b-mu-b-t-an + (dolist (tag tags) + (setq presentp (assoc-default tag bmktags nil t)) + (unless (if nonep (not presentp) presentp) + (throw 'bmkp-b-mu-b-t-an nil))) + t)))) + (forward-line 1) + (if unmarkp (bookmark-bmenu-unmark nil 'NO-RE-SORT-P) (bookmark-bmenu-mark 'NO-RE-SORT-P)) + (setq count (1+ count))))) + (unless no-re-sort-p + ;; If some were (un)marked before but not afterward, and if sort order is `s >', then re-sort. + (when (and (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p)) + (/= nb-marked (length bmkp-bmenu-marked-bookmarks))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p + (if (= 1 count) (message "1 bookmark matched") (message "%d bookmarks matched" count)))))) + +(defun bmkp-bmenu-mark/unmark-bookmarks-tagged-some/not-all (tags &optional notallp unmarkp + no-re-sort-p msg-p) + "Mark or unmark visible bookmarks tagged with any or not all of TAGS. +TAGS is a list of strings, the tag names. +Non-nil NOTALLP means mark/unmark bookmarks that do not have all TAGS. +Non-nil UNMARKP means unmark; nil means mark. +Non-nil NO-RE-SORT-P inhibits re-sorting. +Non-nil MSG-P means display a status message. + +As a special case, if TAGS is empty, then mark or unmark the bookmarks +that have any tags at all, or if NOTALLP is non-nil then mark or +unmark those that have no tags at all. + +If any bookmark was (un)marked before but is not afterward, and if the +sort order is marked first or last (`s >'), then re-sort." + (with-current-buffer bmkp-bmenu-buffer + (let ((count 0) + (nb-marked (length bmkp-bmenu-marked-bookmarks)) + bmktags presentp) + (save-excursion + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (when msg-p (message "Updating bookmark-list display...")) + (while (not (eobp)) + (setq bmktags (bmkp-get-tags (bookmark-bmenu-bookmark))) + (if (not (if (null tags) + (if notallp (not bmktags) bmktags) + (and bmktags (catch 'bmkp-b-mu-b-t-sna + (dolist (tag tags) + (setq presentp (assoc-default tag bmktags nil t)) + (when (if notallp (not presentp) presentp) + (throw 'bmkp-b-mu-b-t-sna t))) + nil)))) + (forward-line 1) + (if unmarkp (bookmark-bmenu-unmark nil 'NO-RE-SORT-P) (bookmark-bmenu-mark 'NO-RE-SORT-P)) + (setq count (1+ count))))) + (unless no-re-sort-p + ;; If some were (un)marked before but not afterward, and if sort order is `s >', then re-sort. + (when (and (equal bmkp-sort-comparer '((bmkp-marked-cp) bmkp-alpha-p)) + (/= nb-marked (length bmkp-bmenu-marked-bookmarks))) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk (bmkp-bmenu-goto-bookmark-named curr-bmk))))) + (when msg-p + (if (= 1 count) (message "1 bookmark matched") (message "%d bookmarks matched" count)))))) + +;;;###autoload (autoload 'bmkp-bmenu-copy-tags "bookmark+") +(defun bmkp-bmenu-copy-tags (&optional msg-p) ; `T c', `T M-w', `mouse-3' menu in bookmark list. + "Copy tags from this bookmark, so you can paste them to another bookmark. +NOTE: It is by design that you can *remove all* tags from a bookmark +by copying an empty set of tags and then pasting to that bookmark +using replacement. So be careful pasting with replacement. If you +want to be sure that you do not replace tags with an empty list of +tags, you can check the value of variable `bmkp-copied-tags' before +pasting." + (interactive (list 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (bmkp-copy-tags (bookmark-bmenu-bookmark) msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-paste-add-tags "bookmark+") +(defun bmkp-bmenu-paste-add-tags (&optional msg-p) ; `T p', `T C-y', `mouse-3' menu in bookmark list. + "Add tags to this bookmark that were copied from another bookmark." + (interactive (list 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (bmkp-paste-add-tags (bookmark-bmenu-bookmark) nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-paste-replace-tags "bookmark+") +(defun bmkp-bmenu-paste-replace-tags (&optional msg-p) ; `T q', `mouse-3' menu. + "Replace tags for this bookmark with those copied from another bookmark. +NOTE: It is by design that you can *remove all* tags from a bookmark +by copying an empty set of tags and then pasting to that bookmark +using this command. So be careful using it. If you want to be sure +that you do not replace tags with an empty list of tags, you can check +the value of variable `bmkp-copied-tags' before pasting." + (interactive (list 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (bmkp-paste-replace-tags (bookmark-bmenu-bookmark) nil msg-p)) + +;;;###autoload (autoload 'bmkp-bmenu-paste-add-tags-to-marked "bookmark+") +(defun bmkp-bmenu-paste-add-tags-to-marked (&optional allp include-omitted-p msg-p) + ; Bound to `T > p', `T > C-y' in bookmark list + "Add tags that were copied from another bookmark to the marked bookmarks. +If no bookmark is marked, act on the bookmark of the current line. + +With a non-negative prefix arg, act on all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included. + +Non-interactively, non-nil MSG-P means display messages." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)) + 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((marked (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p)) + (bmk (bookmark-bmenu-bookmark))) + (unless marked (error "No marked bookmarks")) + (when msg-p (message "Adding tags...")) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk marked) (bmkp-paste-add-tags bmk 'NO-UPDATE-P))) + (bmkp-tags-list) ; Update the tags cache now, after iterate. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh-menu-list bmk (not msg-p)) ; Refresh after iterate. + (when msg-p (message "Tags added: %S" bmkp-copied-tags)))) + +;;;###autoload (autoload 'bmkp-bmenu-paste-replace-tags-for-marked "bookmark+") +(defun bmkp-bmenu-paste-replace-tags-for-marked (&optional allp include-omitted-p msg-p) ; `T > q' + "Replace tags for the marked bookmarks with tags copied previously. +NOTE: It is by design that you can *remove all* tags from a bookmark +by copying an empty set of tags and then pasting to that bookmark +using this command. So be careful using it. If you want to be sure +that you do not replace tags with an empty list of tags, you can check +the value of variable `bmkp-copied-tags' before pasting. + +If no bookmark is marked, act on the bookmark of the current line. + +With a non-negative prefix arg, act on all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included. + +Non-interactively, non-nil MSG-P means display messages." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)) + 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((marked (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p)) + (bmk (bookmark-bmenu-bookmark))) + (unless marked (error "No marked bookmarks")) + (when msg-p (message "Replacing tags...")) + (let ((bookmark-save-flag (and (not bmkp-count-multi-mods-as-one-flag) + bookmark-save-flag))) ; Save at most once, after `dolist'. + (dolist (bmk marked) (bmkp-paste-replace-tags bmk 'NO-UPDATE-P))) + (bmkp-tags-list) ; Update the tags cache now, after iterate. + (bmkp-maybe-save-bookmarks) ; Increments `bookmark-alist-modification-count'. + (bmkp-refresh-menu-list bmk (not msg-p)) ; Refresh after iterate. + (when msg-p (message "Replacement tags: %S" bmkp-copied-tags)))) + + +;;(@* "General Menu-List (`-*bmenu-*') Commands and Functions") +;; *** General Menu-List (`-*bmenu-*') Commands and Functions *** + +;;;###autoload (autoload 'bmkp-bmenu-create/edit-annotations-for-marked "bookmark+") +(defun bmkp-bmenu-edit-annotations-for-marked (&optional allp include-omitted-p) ; `a >' in bookmark list + "Edit the annotations of the marked bookmarks, in separate buffers. +Create an annotation for any marked bookmark that has none. +When you finish editing, use `\\[bmkp-edit-annotations-send]'. +The current bookmark list is then updated to reflect your edits. + +If no bookmark is marked, edit the annotation of the bookmark of the +current line. + +With a non-negative prefix arg, edit annotations for all bookmarks. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-last-bmenu-bookmark (bookmark-bmenu-bookmark)) + ;; No marked bookmarks. Mark this bookmark, so that `C-c C-c' in edit buffer will find it. + (unless bmkp-bmenu-marked-bookmarks (bookmark-bmenu-mark)) + ;; FIXME - Should we re-sort, if it was not annotated and now is, or vice versa, and if `s a'? + ;; We do that for adding/removing tags - see `bmkp-bmenu-add-tags' and `bmkp-bmenu-remove-tags'. + ;; If we do it, then do it also for `bookmark-bmenu-edit-annotation' (which is just vanilla, so far). + (let ((bmks (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p))) + (unless bmks (error "No marked bookmarks")) + (dolist (bmk (bmkp-sort-omit bmks)) (bookmark-edit-annotation bmk)))) + +;;;###autoload (autoload 'bmkp-bmenu-show-or-edit-annotation "bookmark+") +(defun bmkp-bmenu-show-or-edit-annotation (editp msg-p) ; Not bound anymore. + "Show annotation for current bookmark in another window. `C-u': Edit. +With no prefix arg, show the annotation. With a prefix arg, edit it." + (interactive "P\np") + (if editp (bookmark-bmenu-edit-annotation) (bookmark-bmenu-show-annotation msg-p))) + +;;;###autoload (autoload 'bmkp-bmenu-jump-to-marked "bookmark+") +(defun bmkp-bmenu-jump-to-marked () + "Jump to each bookmark marked `>', in another window. +Unlike `bookmark-bmenu-select', this command: +* does not bury buffer `*Bookmark List*' or replace it in its window +* does not unmark the marked bookmarks +* does not include the current bookmark - only the marked are accessed" + (interactive) + (dolist (bmk bmkp-bmenu-marked-bookmarks) + (bookmark-jump-other-window bmk))) + +;;;###autoload (autoload 'bmkp-bmenu-w32-open "bookmark+") +(defun bmkp-bmenu-w32-open () ; Bound to `M-RET' in bookmark list. + "Use `w32-browser' to open this bookmark." + (interactive) (let ((bmkp-use-w32-browser-p t)) (bookmark-bmenu-this-window))) + +;; $$$$$$ FIXME?: If `Open' action opens a window-manager window, it might be behind all Emacs frames. +;;;###autoload (autoload 'bmkp-bmenu-w32-open-with-mouse "bookmark+") +(defun bmkp-bmenu-w32-open-with-mouse (event) ; Bound to `M-mouse-2' in bookmark list. + "Use `w32-browser' to open the bookmark clicked." + (interactive "e") + (let ((bmkp-use-w32-browser-p t) + (bmk (with-current-buffer (window-buffer (posn-window (event-end event))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (save-excursion (goto-char (posn-point (event-end event))) + (bookmark-bmenu-bookmark))))) + (unless bmk (error "No bookmark here")) + (bookmark-handle-bookmark bmk) + ;; Probably do not want this. Users can use `jump-fn' tag if need be. + ;; (let ((orig-buff (current-buffer))) ; Used by `crosshairs-highlight'. + ;; (run-hooks 'bookmark-after-jump-hook)) + (let ((jump-fn (bmkp-get-tag-value bmk "bmkp-jump"))) + (when jump-fn (funcall jump-fn))) + (when bookmark-automatically-show-annotations (bookmark-show-annotation bmk)))) + +;;;###autoload (autoload 'bmkp-bmenu-w32-jump-to-marked "bookmark+") +(defun bmkp-bmenu-w32-jump-to-marked () ; Bound to `M-o' in bookmark-list. + "Use `w32-browser' to open this bookmark and all marked bookmarks." + (interactive) (let ((bmkp-use-w32-browser-p t)) (bmkp-bmenu-jump-to-marked))) + +;;;###autoload (autoload 'bmkp-bmenu-mode-status-help "bookmark+") +(defun bmkp-bmenu-mode-status-help () ; Bound to `C-h m' and `?' in bookmark list + "`describe-mode' + current status of `*Bookmark List*' + face legend." + (interactive) + (unless (string= (buffer-name) "*Help*") (bmkp-bmenu-barf-if-not-in-menu-list)) + (with-current-buffer (get-buffer-create "*Help*") + (bmkp-with-help-window "*Help*" + (let ((buffer-read-only nil) + top) + (erase-buffer) + (save-excursion + (let ((standard-output (current-buffer))) + (if (> emacs-major-version 21) + (describe-function-1 'bookmark-bmenu-mode) + (describe-function-1 'bookmark-bmenu-mode nil t))) + (help-setup-xref (list #'bmkp-bmenu-mode-status-help) (interactive-p)) + (goto-char (point-min)) + (search-forward ; This depends on the text written by `bookmark-bmenu-mode'. + "More bookmarking help below." nil t) + (delete-region (point-min) (point)) ; Get rid of intro from `describe-function'. + (insert "*************************** Bookmark List ***************************\n\n") + (insert "Major mode for editing a list of bookmarks.\n") + (insert "Each line in `*Bookmark List*' represents an Emacs bookmark.\n") + (setq top (copy-marker (point))) + ;; Add buttons to access help and Customize. + ;; Not for Emacs 21.3 - its `help-insert-xref-button' signature is different. + (when (and (> emacs-major-version 21) ; In `help-mode.el'. + (condition-case nil (require 'help-mode nil t) (error nil)) + (fboundp 'help-insert-xref-button)) + (goto-char (point-min)) + (help-insert-xref-button "[Doc in Commentary]" 'bmkp-commentary-button) + (insert " ") + (help-insert-xref-button "[Doc on the Web]" 'bmkp-help-button) + (insert " ") + (help-insert-xref-button "[Customize]" 'bmkp-customize-button) + (insert "\n\n") + (goto-char (point-max)) + (insert (substitute-command-keys + "\nSend a Bookmark+ bug report: `\\[bmkp-send-bug-report]'.\n\n")) + (help-insert-xref-button "[Doc in Commentary]" 'bmkp-commentary-button) + (insert " ") + (help-insert-xref-button "[Doc on the Web]" 'bmkp-help-button) + (insert " ") + (help-insert-xref-button "[Customize]" 'bmkp-customize-button) + (insert "\n\n") + (goto-char (point-min)) + (forward-line 2)) + (goto-char top) + (insert (format + "\n\nCurrent Status\n--------------\n +Bookmark file:\t%s\nSorted:\t\t\t%s\nFiltering:\t\t%s\nMarked:\t\t\t%d\nOmitted:\t\t%d\n\ +Autosave bookmarks:\t%s\nAutosave list display:\t%s\n\n\n" + bmkp-current-bookmark-file + (if (not bmkp-sort-comparer) + "no" + (format "%s%s" (or (bmkp-current-sort-order) "") + ;; Code essentially the same as found in `bmkp-msg-about-sort-order'. + (if (not (and (consp bmkp-sort-comparer) ; Ordinary single predicate + (consp (car bmkp-sort-comparer)))) + (if bmkp-reverse-sort-p "; reversed" "") + (if (not (cadr (car bmkp-sort-comparer))) + ;; Single PRED. + (if (or (and bmkp-reverse-sort-p (not bmkp-reverse-multi-sort-p)) + (and bmkp-reverse-multi-sort-p (not bmkp-reverse-sort-p))) + "; reversed" + "") + ;; In case we want to distinguish: + ;; (if (and bmkp-reverse-sort-p + ;; (not bmkp-reverse-multi-sort-p)) + ;; "; reversed" + ;; (if (and bmkp-reverse-multi-sort-p + ;; (not bmkp-reverse-sort-p)) + ;; "; reversed +" + ;; "")) + + ;; At least two PREDs. + (cond ((and bmkp-reverse-sort-p (not bmkp-reverse-multi-sort-p)) + "; reversed") + ((and bmkp-reverse-multi-sort-p (not bmkp-reverse-sort-p)) + "; each predicate group reversed") + ((and bmkp-reverse-multi-sort-p bmkp-reverse-sort-p) + "; order of predicate groups reversed") + (t "")))))) + (or (and bmkp-bmenu-filter-function (downcase bmkp-bmenu-title)) "none") + (length bmkp-bmenu-marked-bookmarks) + (length bmkp-bmenu-omitted-bookmarks) + (if bookmark-save-flag "yes" "no") + (if bmkp-bmenu-state-file "yes" "no"))) + + ;; Add markings legend. + (let ((mm " >") + (DD " D") + (tt " t") + (aa " a") + (XX " X") + (mod " *")) + (put-text-property 2 3 'face 'bmkp->-mark mm) + (put-text-property 2 3 'face 'bmkp-D-mark DD) + (put-text-property 2 3 'face 'bmkp-t-mark tt) + (put-text-property 2 3 'face 'bmkp-a-mark aa) + (put-text-property 2 3 'face 'bmkp-X-mark XX) + (put-text-property 2 3 'face 'bmkp-*-mark mod) + (insert "Legend for Markings\n-------------------\n\n") + (insert (concat mm " marked\n")) + (insert (concat DD " flagged for deletion (`x' to delete all such)\n")) + (insert (concat tt " tagged (`C-h C-RET' to see)\n")) + (insert (concat aa " annotated (`C-h C-RET' to see)\n")) + (insert (concat mod " modified (not saved)\n")) + (insert (concat XX " temporary (will not be saved)\n")) + (insert "\n\n")) + + ;; Add face legend. + (let ((gnus "Gnus\n") + (no-jump "Bookmarks you cannot jump to from `*Bookmark List*'\n") + (info "Info node\n") + (man "Man page\n") + (url "URL\n") + (local-no-region "Local file with no region\n") + (local-w-region "Local file with a region\n") + (no-file "No such local file\n") + (buffer "Buffer\n") + (no-buf "No such buffer now\n") + (bad "Possibly invalid bookmark\n") + (remote "Remote file/directory or Dired buffer (could have wildcards)\n") + (sudo "Remote accessed by `su' or `sudo'\n") + (local-dir "Local directory or Dired buffer (could have wildcards)\n") + (file-handler "Bookmark with entry `file-handler'\n") + (bookmark-list "*Bookmark List*\n") + (bookmark-file "Bookmark file\n") + (snippet "Snippet\n") + (desktop "Desktop\n") + (sequence "Sequence\n") + (variable-list "Variable list\n") + (function "Function\n")) + (put-text-property 0 (1- (length gnus)) 'face 'bmkp-gnus gnus) + (put-text-property 0 (1- (length info)) 'face 'bmkp-info info) + (put-text-property 0 (1- (length man)) 'face 'bmkp-man man) + (put-text-property 0 (1- (length url)) 'face 'bmkp-url url) + (put-text-property 0 (1- (length local-no-region)) + 'face 'bmkp-local-file-without-region local-no-region) + (put-text-property 0 (1- (length local-w-region)) + 'face 'bmkp-local-file-with-region local-w-region) + (put-text-property 0 (1- (length no-file)) 'face 'bmkp-no-local no-file) + (put-text-property 0 (1- (length buffer)) 'face 'bmkp-buffer buffer) + (put-text-property 0 (1- (length no-buf)) 'face 'bmkp-non-file no-buf) + (put-text-property 0 (1- (length remote)) 'face 'bmkp-remote-file remote) + (put-text-property 0 (1- (length sudo)) 'face 'bmkp-su-or-sudo sudo) + (put-text-property 0 (1- (length local-dir)) + 'face 'bmkp-local-directory local-dir) + (put-text-property 0 (1- (length file-handler)) 'face 'bmkp-file-handler file-handler) + (put-text-property 0 (1- (length bookmark-list)) + 'face 'bmkp-bookmark-list bookmark-list) + (put-text-property 0 (1- (length bookmark-file)) + 'face 'bmkp-bookmark-file bookmark-file) + (put-text-property 0 (1- (length snippet)) 'face 'bmkp-snippet snippet) + (put-text-property 0 (1- (length desktop)) 'face 'bmkp-desktop desktop) + (put-text-property 0 (1- (length sequence)) 'face 'bmkp-sequence sequence) + (put-text-property 0 (1- (length variable-list)) 'face 'bmkp-variable-list variable-list) + (put-text-property 0 (1- (length function)) 'face 'bmkp-function function) + (put-text-property 0 (1- (length no-jump)) 'face 'bmkp-no-jump no-jump) + (put-text-property 0 (1- (length bad)) 'face 'bmkp-bad-bookmark bad) + (insert "Legend for Bookmark Types\n-------------------------\n\n") + (when (and (fboundp 'display-images-p) (display-images-p) + bmkp-bmenu-image-bookmark-icon-file + (file-readable-p bmkp-bmenu-image-bookmark-icon-file)) + (let ((image (create-image bmkp-bmenu-image-bookmark-icon-file nil nil :ascent 95))) + (when image (insert " ") (insert-image image) (insert " Image file\n")))) + (insert " " gnus) (insert " " info) (insert " " man) (insert " " url) + (insert " " local-no-region) (insert " " local-w-region) (insert " " no-file) + (insert " " buffer) (insert " " no-buf) (insert " " remote) (insert " " sudo) + (insert " " local-dir) (insert " " file-handler) (insert " " bookmark-list) + (insert " " bookmark-file) (insert " " snippet) (insert " " desktop) + (insert " " sequence) (insert " " variable-list) (insert " " function) + (insert " " no-jump) (insert " " bad) + (insert "\n\nKeys without prefix `C-x' are available only here (`*Bookmark List*').\n") + (insert "Keys with prefix `C-x' are available everywhere.\n\n") + (insert "Remember that you can see all bindings for a prefix key by hitting it,\n") + (insert "then `C-h'. E.g., `s C-h' to see keys with prefix `s' (sorting)."))))))) + +(when (and (> emacs-major-version 21) + (condition-case nil (require 'help-mode nil t) (error nil)) + (get 'help-xref 'button-category-symbol)) ; In `button.el' + (define-button-type 'bmkp-help-button + :supertype 'help-xref + 'help-function #'(lambda () (browse-url "https://www.emacswiki.org/emacs/BookmarkPlus")) + 'help-echo + (purecopy "mouse-2, RET: Bookmark+ documentation on the Emacs Wiki (requires Internet access)")) + (define-button-type 'bmkp-commentary-button + :supertype 'help-xref + 'help-function #'(lambda () + (message "Getting Bookmark+ doc from file commentary...") + (finder-commentary "bookmark+-doc") + (when (condition-case nil (require 'linkd nil t) (error nil)) (linkd-mode 1)) + (when (condition-case nil (require 'fit-frame nil t) (error nil)) + (fit-frame))) + 'help-echo (purecopy "mouse-2, RET: Bookmark+ documentation (no Internet needed)")) + (define-button-type 'bmkp-customize-button + :supertype 'help-xref + 'help-function #'(lambda () (customize-group-other-window 'bookmark-plus)) + 'help-echo (purecopy "mouse-2, RET: Customize/Browse Bookmark+ Options & Faces"))) + +;;;###autoload (autoload 'bmkp-bmenu-define-jump-marked-command "bookmark+") +(defun bmkp-bmenu-define-jump-marked-command () ; Bound to `C-c C-j' in bookmark list + "Define a command to jump to a bookmark that is one of those now marked. +The bookmarks marked now will be those that are completion candidates +for the command (but omitted bookmarks are excluded). +Save the command definition in `bmkp-bmenu-commands-file'." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let* ((cands (mapcar #'list + (bmkp-maybe-unpropertize-bookmark-names + (bmkp-remove-if #'(lambda (bmk) + (bmkp-bookmark-name-member bmk bmkp-bmenu-omitted-bookmarks)) + bmkp-bmenu-marked-bookmarks)))) + (fn (intern (read-string "Define command to jump to a bookmark now marked: " nil + bmkp-bmenu-define-command-history))) + (def `(defun ,fn (bookmark-name &optional flip-use-region-p) + (interactive (list (bmkp-read-bookmark-for-type nil ',cands t) current-prefix-arg)) + (bmkp-jump-1 bookmark-name 'bmkp-select-buffer-other-window flip-use-region-p)))) + (eval def) + (with-current-buffer (find-file-noselect bmkp-bmenu-commands-file) + (goto-char (point-max)) + (let ((print-length nil) + (print-level nil) + (print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag) + (version-control (case bookmark-version-control + ((nil) nil) + (never 'never) + (nospecial version-control) + (t t))) + (require-final-newline t) + (errorp nil)) + (pp def (current-buffer)) + (insert "\n") + (condition-case nil + (write-file bmkp-bmenu-commands-file) + (file-error (setq errorp t) (error "CANNOT WRITE FILE `%s'" bmkp-bmenu-commands-file))) + (kill-buffer (current-buffer)) + (unless errorp (message "Command `%s' defined and saved in file `%s'" + fn bmkp-bmenu-commands-file)))))) + +;;;###autoload (autoload 'bmkp-bmenu-define-command "bookmark+") +(defun bmkp-bmenu-define-command () ; Bound to `C-c C-c' in bookmark list + "Define a command to use the current sort order, filter, and omit list. +Prompt for the command name. Save the command definition in +`bmkp-bmenu-commands-file'. + +The current sort order, filter function, omit list, and title for +buffer `*Bookmark List*' are encapsulated as part of the command. +Use the command at any time to restore them." + (interactive) + (let* ((fn (intern (read-string "Define sort+filter command: " nil + bmkp-bmenu-define-command-history))) + (_IGNORE (when (fboundp fn) + (if (y-or-n-p (format "`%s' already defined. Redfine? " fn)) + (fmakunbound fn) + (error "OK, canceled")))) + (def `(defun ,fn () + (interactive) + (setq + bmkp-sort-comparer ',bmkp-sort-comparer + bmkp-reverse-sort-p ',bmkp-reverse-sort-p + bmkp-reverse-multi-sort-p ',bmkp-reverse-multi-sort-p + bmkp-bmenu-filter-function ',bmkp-bmenu-filter-function + bmkp-bmenu-filter-pattern ',bmkp-bmenu-filter-pattern + ;; Use `copy-sequence' here, because some code modifies the list structure. + bmkp-bmenu-omitted-bookmarks (copy-sequence + ',(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-omitted-bookmarks)) + bmkp-bmenu-title ',bmkp-bmenu-title + bookmark-bmenu-toggle-filenames ',bookmark-bmenu-toggle-filenames) + (bmkp-bmenu-refresh-menu-list) + (when (interactive-p) + (bmkp-msg-about-sort-order + (car (rassoc bmkp-sort-comparer bmkp-sort-orders-alist))))))) + (eval def) + (with-current-buffer (find-file-noselect bmkp-bmenu-commands-file) + (goto-char (point-min)) ; Delete any preexisting defs of the same command. + (let (sexp) + (condition-case nil + (while (setq sexp (read (current-buffer))) + (when (and (consp sexp) (eq 'defun (car sexp)) + (eq fn (cadr sexp))) + (delete-region (point) (save-excursion (backward-sexp) (point))))) + (error nil))) + (goto-char (point-max)) + (let ((print-length nil) + (print-level nil) + (print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag) + (version-control (case bookmark-version-control + ((nil) nil) + (never 'never) + (nospecial version-control) + (t t))) + (require-final-newline t) + (errorp nil)) + (pp def (current-buffer)) + (insert "\n") + (condition-case nil + (write-file bmkp-bmenu-commands-file) + (file-error (setq errorp t) (error "CANNOT WRITE FILE `%s'" bmkp-bmenu-commands-file))) + (kill-buffer (current-buffer)) + (unless errorp (message "Command `%s' defined and saved in file `%s'" + fn bmkp-bmenu-commands-file)))))) + +;;;###autoload (autoload 'bmkp-bmenu-define-full-snapshot-command "bookmark+") +(defun bmkp-bmenu-define-full-snapshot-command () ; Bound to `C-c C-S-c' (aka `C-c C-C') in bookmark list + "Define a command to restore the current bookmark-list state. +Prompt for the command name. Save the command definition in +`bmkp-bmenu-commands-file'. + +Be aware that the command definition can be quite large, since it +copies the current bookmark list and accessory lists (hidden +bookmarks, marked bookmarks, etc.). For a lighter weight command, use +`bmkp-bmenu-define-full-snapshot-command' instead. That records only +the omit list and the sort & filter information." + (interactive) + (let* ((fn (intern (read-string "Define restore-snapshot command: " nil + bmkp-bmenu-define-command-history))) + (_IGNORE (when (fboundp fn) + (if (y-or-n-p (format "`%s' already defined. Redfine? " fn)) + (fmakunbound fn) + (error "OK, canceled")))) + (def `(defun ,fn () + (interactive) + ;; Use `copy-sequence' here, to avoid circular references when + ;; `bmkp-propertize-bookmark-names-flag' is nil, and for other + ;; strings and lists (such as `bmkp-bmenu-marked-bookmarks'), + ;; because some code modifies them. + ;; + (setq + bmkp-sort-comparer ',bmkp-sort-comparer + bmkp-reverse-sort-p ',bmkp-reverse-sort-p + bmkp-reverse-multi-sort-p ',bmkp-reverse-multi-sort-p + bmkp-latest-bookmark-alist (copy-sequence + ',(bmkp-maybe-unpropertize-bookmark-names + bmkp-latest-bookmark-alist)) + bmkp-bmenu-omitted-bookmarks (copy-sequence + ',(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-omitted-bookmarks 'COPY)) + bmkp-bmenu-marked-bookmarks (copy-sequence + ',(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-marked-bookmarks 'COPY)) + bmkp-bmenu-filter-function ',bmkp-bmenu-filter-function + bmkp-bmenu-filter-pattern ',bmkp-bmenu-filter-pattern + bmkp-bmenu-title ',bmkp-bmenu-title + bmkp-last-bmenu-bookmark ',(and (get-buffer bmkp-bmenu-buffer) + (with-current-buffer + (get-buffer bmkp-bmenu-buffer) + (bmkp-maybe-unpropertize-string + (bookmark-bmenu-bookmark) 'COPY))) + bmkp-last-specific-buffer ',(copy-sequence bmkp-last-specific-buffer) + bmkp-last-specific-file ',(copy-sequence bmkp-last-specific-file) + bookmark-bmenu-toggle-filenames ',bookmark-bmenu-toggle-filenames + bmkp-bmenu-before-hide-marked-alist (copy-sequence + ',(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-before-hide-marked-alist 'COPY)) + bmkp-bmenu-before-hide-unmarked-alist (copy-sequence + ',(bmkp-maybe-unpropertize-bookmark-names + bmkp-bmenu-before-hide-unmarked-alist 'COPY)) + bmkp-last-bookmark-file ',(copy-sequence + (convert-standard-filename + (expand-file-name bmkp-last-bookmark-file))) + bmkp-current-bookmark-file ',(copy-sequence + (convert-standard-filename + (expand-file-name + bmkp-current-bookmark-file)))) + ;; $$$$$$ (let ((bookmark-alist (bmkp-refresh-latest-bookmark-list))) ; Sets *-latest-* also. + (let ((bookmark-alist (or bmkp-latest-bookmark-alist + (bmkp-refresh-latest-bookmark-list)))) ; Sets *-latest-* also. + (bmkp-bmenu-list-1 'filteredp nil (interactive-p))) + (when bmkp-last-bmenu-bookmark + (with-current-buffer (get-buffer bmkp-bmenu-buffer) + (bmkp-bmenu-goto-bookmark-named bmkp-last-bmenu-bookmark))) + (when (interactive-p) + (bmkp-msg-about-sort-order (car (rassoc bmkp-sort-comparer bmkp-sort-orders-alist))))))) + (eval def) + (with-current-buffer (find-file-noselect bmkp-bmenu-commands-file) + (goto-char (point-min)) ; Delete any preexisting defs of the same command. + (let (sexp) + (condition-case nil + (while (setq sexp (read (current-buffer))) + (when (and (consp sexp) (eq 'defun (car sexp)) + (eq fn (cadr sexp))) + (delete-region (point) (save-excursion (backward-sexp) (point))))) + (error nil))) + (goto-char (point-max)) + (let ((print-length nil) + (print-level nil) + (print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag) + (version-control (case bookmark-version-control + ((nil) nil) + (never 'never) + (nospecial version-control) + (t t))) + (require-final-newline t) + (errorp nil)) + (pp def (current-buffer)) + (insert "\n") + (condition-case nil + (write-file bmkp-bmenu-commands-file) + (file-error (setq errorp t) (error "CANNOT WRITE FILE `%s'" bmkp-bmenu-commands-file))) + (kill-buffer (current-buffer)) + (unless errorp (message "Command `%s' defined and saved in file `%s'" + fn bmkp-bmenu-commands-file)))))) + +;; We use this because Emacs 20 has no `print-circle' or `print-gensym'. and otherwise +;; property `bmkp-full-record' would make the state file unreadable. +;; +(defun bmkp-maybe-unpropertize-bookmark-names (list &optional copy) + "Strip properties from the bookmark names in a copy of LIST. +LIST is a bookmark alist or a list of bookmark names (strings). +Return the updated copy. + +Note, however, that this is a shallow copy, so the names are also +stripped within any alist elements of the original LIST. + +Non-nil optional arg COPY means copy also each element of LIST. Use +this if, for example, you have bookmark lists that share bookmarks and +you want to treat the shared bookmarks separately. + +Always strip property `face' and internal Icicles properties. Remove +other text properties only if using Emacs 20 or if option +`bmkp-propertize-bookmark-names-flag' is non-nil." + (let ((new-list (copy-sequence list)) + (rem-all-p (or (not bmkp-propertize-bookmark-names-flag) + (< emacs-major-version 21)))) ; Cannot just use (not (boundp 'print-circle)). + (dolist (bmk new-list) + (when (and (consp bmk) (stringp (car bmk))) (setq bmk (car bmk))) + (when (stringp bmk) + (let ((len (length bmk))) + (if rem-all-p + (set-text-properties 0 len nil bmk) + (remove-text-properties ; Remove property `face' and any Icicles internal properties. + 0 len '(face nil + display nil + help-echo nil + rear-nonsticky nil + icicle-fancy-candidates nil + icicle-mode-line-help nil + icicle-special-candidate nil + icicle-user-plain-dot nil + icicle-whole-candidate nil + invisible nil) + bmk) + (when (boundp 'icicle-candidate-properties-alist) ; Multi-completion indexes + text props. + (dolist (entry icicle-candidate-properties-alist) + (put-text-property 0 len (car (cadr entry)) nil bmk))))))) + (if copy (mapcar #'copy-sequence new-list) new-list))) + +(defun bmkp-maybe-unpropertize-string (string &optional copy) + "Strip properties from STRING. +Return the unpropertized STRING. +Non-nil optional arg COPY means return a copy of the unpropertized +STRING. (STRING is modified before the copy is made.) + +Do nothing in Emacs 21 or later or if +`bmkp-propertize-bookmark-names-flag' is non-nil. In these cases, +just return STRING unmodified." + (unless (and (> emacs-major-version 20) ; Emacs 21+. Cannot just use (boundp 'print-circle). + bmkp-propertize-bookmark-names-flag) + (set-text-properties 0 (length string) nil string) + (when copy (setq string (copy-sequence string)))) + string) + +;; This is a general command. It is in this file because it uses macro `bmkp-define-sort-command' +;; and it is used mainly in the bookmark list display. +;;;###autoload (autoload 'bmkp-define-tags-sort-command "bookmark+") +(defun bmkp-define-tags-sort-command (tags &optional msg-p) ; Bound to `T s' in bookmark list + "Define a command to sort bookmarks in the bookmark list by tags. +Hit `RET' to enter each tag, then hit `RET' again after the last tag. + +The new command sorts first by the first tag in TAGS, then by the +second, and so on. + +Besides sorting for these specific tags, any bookmark that has a tag +sorts before one that has no tags. Otherwise, sorting is by bookmark +name, alphabetically. + +The name of the new command is `bmkp-bmenu-sort-' followed by the +specified tags, in order, separated by hyphens (`-'). E.g., for TAGS +\(\"alpha\" \"beta\"), the name is `bmkp-bmenu-sort-alpha-beta'. + +If you use this function non-interactively, be sure to load library +`bookmark+-mac.el' first." + (interactive + (progn (or (condition-case nil ; Load `bookmark+-mac.el' when called interactively. + (load-library "bookmark+-mac") ; Use load-library to ensure latest .elc. + (error nil)) + (require 'bookmark+-mac)) + (list (bmkp-read-tags-completing) 'MSG))) + (let ((sort-order (concat "tags-" (mapconcat #'identity tags "-"))) + (doc-string (read-string "Doc string for command: ")) + (comparer ()) + def) + (dolist (tag tags) + (push `(lambda (b1 b2) + (let ((tags1 (bmkp-get-tags b1)) + (tags2 (bmkp-get-tags b2))) + (cond ((and (assoc-default ,tag tags1 nil t) + (assoc-default ,tag tags2 nil t)) nil) + ((assoc-default ,tag tags1 nil t) '(t)) + ((assoc-default ,tag tags2 nil t) '(nil)) + ((and tags1 tags2) nil) + (tags1 '(t)) + (tags2 '(nil)) + (t nil)))) + comparer)) + (setq comparer (nreverse comparer) + comparer (list comparer 'bmkp-alpha-p)) + (eval (setq def (macroexpand `(bmkp-define-sort-command ,sort-order ,comparer ,doc-string)))) + (with-current-buffer (find-file-noselect bmkp-bmenu-commands-file) + (goto-char (point-max)) + (let ((print-length nil) + (print-level nil) + (print-circle bmkp-propertize-bookmark-names-flag) + (print-gensym bmkp-propertize-bookmark-names-flag) + (version-control (case bookmark-version-control + ((nil) nil) + (never 'never) + (nospecial version-control) + (t t))) + (require-final-newline t) + (errorp nil)) + (pp def (current-buffer)) + (insert "\n") + (condition-case nil + (write-file bmkp-bmenu-commands-file) + (file-error (setq errorp t) (error "CANNOT WRITE FILE `%s'" bmkp-bmenu-commands-file))) + (kill-buffer (current-buffer)) + (when (and msg-p (not errorp)) + (message "Defined and saved command `%s'" (concat "bmkp-bmenu-sort-" sort-order))))))) + +;;;###autoload (autoload 'bmkp-bmenu-relocate-marked "bookmark+") +(defun bmkp-bmenu-relocate-marked (directory &optional include-omitted-p msgp) + ; Bound to `M-R' in bookmark list + "Relocate target files of all (visible) bookmarks that are marked `>'. +You are prompted for the relocation target directory. +Return the number of bookmarks relocated to DIRECTORY. + +Omitted bookmarks are excluded, by default. With a prefix arg, any +that are marked are included. + +Non-interactively, non-nil MSG-P means display messages." + (interactive (list (funcall (if (fboundp 'read-directory-name) + #'read-directory-name + #'read-file-name) + "Relocate targets of marked bookmarks to directory: " + default-directory default-directory) + current-prefix-arg + 'MSGP)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((count 0) + file) + (dolist (bmk (bmkp-sort-omit (bmkp-bmenu-marked-or-this-or-all nil include-omitted-p))) + (when (and (setq file (bookmark-get-filename bmk)) + (not (equal file bmkp-non-file-filename))) + (setq file (file-name-nondirectory file) + count (1+ count)) + (bookmark-set-filename bmk (expand-file-name file directory)) + (setq bookmark-alist-modification-count + (1+ bookmark-alist-modification-count)))) + (when (bookmark-time-to-save-p) (bookmark-save)) + (bookmark-bmenu-surreptitiously-rebuild-list) + (when msgp + (if (> count 0) + (message "Relocated %d bookmark%s" count (if (= 1 count) "" "s")) + (message "No bookmarks relocated"))) + count)) + +;;;###autoload (autoload 'bmkp-copy-bookmark "bookmark+") +(defalias 'bmkp-bmenu-copy-bookmark 'bmkp-bmenu-clone-bookmark) +;;;###autoload (autoload 'bmkp-bmenu-clone-bookmark "bookmark+") +(defun bmkp-bmenu-clone-bookmark (&optional arg confirm-overwrite-p) ; Bound to `M-n' in bookmark list + "Create a duplicate copy named of the bookmark under the cursor. +The clone name is the same as that bookmark, but with \"<2>\" appended. +With a prefix arg you are instead prompted for the clone name." + (interactive "P\np") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let* ((orig (bookmark-bmenu-bookmark)) + ;; Remove any `bmkp-full-record' property from name. + (_IGNORE (remove-text-properties 0 (length orig) '(bmkp-full-record nil) orig)) + (default (concat orig "<2>")) + (new (if arg + (bmkp-completing-read-lax "Clone name" default) + default))) + (while (equal orig new) + (setq new (bmkp-completing-read-lax "Clone name (must be different)" default))) + ;; Remove any `bmkp-full-record' property from name. + (remove-text-properties 0 (length new) '(bmkp-full-record nil) new) + (bmkp-clone-bookmark orig new confirm-overwrite-p))) + +;;;###autoload (autoload 'bmkp-bmenu-edit-bookmark-name-and-location "bookmark+") +(defun bmkp-bmenu-edit-bookmark-name-and-location (&optional internalp) ; Bound to `r' in bookmark list + "Edit the bookmark under the cursor: its name and location. +With a prefix argument, edit the complete bookmark record (the +internal, Lisp form)." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (let ((bmk-name (bookmark-bmenu-bookmark))) + (if internalp + (bmkp-edit-bookmark-record bmk-name) + (let* ((new-data (bmkp-edit-bookmark-name-and-location bmk-name)) + (new-name (car new-data))) + (if (not new-data) (message "No changes made") (bmkp-refresh-menu-list new-name)))))) + +;;;###autoload (autoload 'bmkp-bmenu-edit-tags "bookmark+") +(defun bmkp-bmenu-edit-tags () ; Bound to `T e' in bookmark list + "Edit the tags of the bookmark under the cursor. +The edited value must be a list each of whose elements is either a +string or a cons whose key is a string." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (bmkp-edit-tags (bookmark-bmenu-bookmark))) + +;;;###autoload (autoload 'bmkp-bmenu-edit-bookmark-record "bookmark+") +(defun bmkp-bmenu-edit-bookmark-record () ; Bound to `e' in bookmark list + "Edit the full record (the Lisp sexp) for the bookmark under the cursor. +When you finish editing, use `\\[bmkp-edit-bookmark-record-send]'. +The current bookmark list is then updated to reflect your edits." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bookmark-bmenu-ensure-position) + (bmkp-edit-bookmark-record (setq bmkp-edit-bookmark-orig-record (bookmark-bmenu-bookmark)))) + +;;;###autoload (autoload 'bmkp-bmenu-edit-marked "bookmark+") +(defun bmkp-bmenu-edit-marked (&optional allp include-omitted-p) ; Bound to `E' in bookmark list + "Edit the full records (the Lisp sexps) of the marked bookmarks. +If no bookmarks are marked then mark the bookmark on the current line, +and edit its record. + +When you finish editing, use `\\[bmkp-edit-bookmark-records-send]'. +The current bookmark list is then updated to reflect your edits. + +If no bookmark is marked, edit the bookmark of the current line. + +With a non-negative prefix arg, edit all bookmark records. + +Omitted bookmarks are excluded, by default. With a negative prefix +arg, any that are marked are included." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (< (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-last-bmenu-bookmark (bookmark-bmenu-bookmark)) + ;; No marked bookmarks. Mark this bookmark, so that `C-c C-c' in edit buffer will find it. + ;; Do this before we copy and strip full-bookmark property from name, because `bookmark-bmenu-mark' + ;; propertizes the name. + (unless bmkp-bmenu-marked-bookmarks (bookmark-bmenu-mark)) + (let ((bufname "*Edit Marked Bookmarks*") + (copied-bmks (mapcar (lambda (bmk) + (setq bmk (copy-sequence bmk)) ; Shallow copy + (let ((bname (bmkp-bookmark-name-from-record bmk))) + ;; Strip properties from name. + (set-text-properties 0 (length bname) nil bname)) + bmk) + (bmkp-bmenu-marked-or-this-or-all allp include-omitted-p)))) + (unless copied-bmks (error "No marked bookmarks")) + (setq bmkp-edit-bookmark-records-number (length copied-bmks)) + (bmkp-with-output-to-plain-temp-buffer bufname + (princ (substitute-command-keys + (concat ";; Edit the Lisp records for the marked bookmarks.\n;;\n" + ";; DO NOT CHANGE THE ORDER of the bookmarks in this buffer.\n" + ";; DO NOT DELETE any of them.\n;;\n" + ";; Type \\\ +`\\[bmkp-edit-bookmark-records-send]' when done.\n;;\n"))) + ;; $$$$$$ (let ((print-circle t)) (pp copied-bmks)) ; $$$$$$ Should not really be needed now. + (pp copied-bmks) + (with-current-buffer bufname + (goto-char (point-min)) + (buffer-enable-undo))) + (pop-to-buffer bufname) + (with-current-buffer (get-buffer bufname) (bmkp-edit-bookmark-records-mode)))) + +(defun bmkp-bmenu-propertize-item (bookmark start end) + "Propertize text in buffer from START to END, indicating bookmark type. +This propertizes the name of BOOKMARK. +Also give this region the property `bmkp-bookmark-name' with as value +the name of BOOKMARK as a propertized string. + +The propertized string has property `bmkp-full-record' with value +BOOKMARK, which is the full bookmark record, with the string as its +car. + +Return the propertized string (the bookmark name)." + (setq bookmark (bmkp-get-bookmark bookmark)) + (let* ((bookmark-name (bmkp-bookmark-name-from-record bookmark)) + (buffp (bmkp-get-buffer-name bookmark)) + + (filep (bookmark-get-filename bookmark)) + (sudop (and filep (boundp 'tramp-file-name-regexp) + (bmkp-string-match-p tramp-file-name-regexp filep) + (bmkp-string-match-p bmkp-su-or-sudo-regexp filep)))) + ;; Put the full bookmark itself on string `bookmark-name' as property `bmkp-full-record'. + ;; Then put that string on the name in the buffer text as property `bmkp-bookmark-name'. + (put-text-property 0 (length bookmark-name) 'bmkp-full-record bookmark bookmark-name) + (put-text-property start end 'bmkp-bookmark-name bookmark-name) + ;; Add faces, mouse face, and tooltips, to characterize the bookmark type. + (add-text-properties + start end + (cond ((bookmark-prop-get bookmark 'file-handler) ; `file-handler' bookmark + (append (bmkp-face-prop 'bmkp-file-handler) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Invoke the `file-handler' for this bookmark"))) + ((bmkp-sequence-bookmark-p bookmark) ; Sequence bookmark + (append (bmkp-face-prop 'bmkp-sequence) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Invoke the bookmarks in this sequence"))) + ((bmkp-function-bookmark-p bookmark) ; Function bookmark + (append (bmkp-face-prop 'bmkp-function) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Invoke this function bookmark"))) + ((bmkp-variable-list-bookmark-p bookmark) ; Variable-list bookmark + (append (bmkp-face-prop 'bmkp-variable-list) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Invoke this variable-list bookmark"))) + ((bmkp-bookmark-list-bookmark-p bookmark) ; Bookmark-list bookmark + (append (bmkp-face-prop 'bmkp-bookmark-list) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Invoke this bookmark-list bookmark"))) + ((bmkp-snippet-bookmark-p bookmark) ; Snippet bookmark + (append (bmkp-face-prop 'bmkp-snippet) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Jump to this snippet bookmark"))) + ((bmkp-desktop-bookmark-p bookmark) ; Desktop bookmark + (append (bmkp-face-prop 'bmkp-desktop) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Jump to this desktop bookmark"))) + ((bmkp-bookmark-file-bookmark-p bookmark) ; Bookmark-file bookmark + (append (bmkp-face-prop 'bmkp-bookmark-file) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Load this bookmark's bookmark file"))) + ((bmkp-non-invokable-bookmark-p bookmark) ; Non-invokable bookmark + (append (bmkp-face-prop 'bmkp-no-jump) + '(help-echo "You CANNOT JUMP to this bookmark"))) + ((bmkp-icicles-search-hits-bookmark-p bookmark) ; Icicles search hits bookmark + (append (bmkp-face-prop 'bmkp-no-jump) + '(help-echo "You can use this only during Icicles search, NOT HERE"))) + ((bmkp-info-bookmark-p bookmark) ; Info bookmark + (append (bmkp-face-prop 'bmkp-info) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Jump to this Info bookmark"))) + ((bmkp-man-bookmark-p bookmark) ; Man bookmark + (append (bmkp-face-prop 'bmkp-man) + '(mouse-face highlight follow-link t + help-echo (format "mouse-2 Goto `man' page")))) + ((bmkp-gnus-bookmark-p bookmark) ; Gnus bookmark + (append (bmkp-face-prop 'bmkp-gnus) + '(mouse-face highlight follow-link t + help-echo "mouse-2: Jump to this Gnus bookmark"))) + ((bmkp-url-bookmark-p bookmark) ; URL bookmark + (append (bmkp-face-prop 'bmkp-url) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Jump to URL `%s'" ,filep)))) + ((and sudop (not (bmkp-root-or-sudo-logged-p))) ; Root/sudo not logged in + (append (bmkp-face-prop 'bmkp-su-or-sudo) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Jump to (visit) file `%s'" ,filep)))) + ;; Test for remoteness before any other tests of the file itself + ;; (e.g. `file-exists-p'), so Tramp does not prompt for a password etc. + ((and filep (bmkp-file-remote-p filep) (not sudop)) ; Remote file (ssh, ftp) + (append (bmkp-face-prop 'bmkp-remote-file) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Jump to (visit) remote file `%s'" ,filep)))) + ((and filep ; Local directory or local Dired buffer (could be wildcards) + (or (file-directory-p filep) (bmkp-dired-bookmark-p bookmark))) + (append (bmkp-face-prop 'bmkp-local-directory) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Dired directory `%s'" ,filep)))) + ((and filep (file-exists-p filep) ; Local file with region + (bmkp-region-bookmark-p bookmark)) + (append (bmkp-face-prop 'bmkp-local-file-with-region) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Activate region in file `%s'" ,filep)))) + ((and filep (file-exists-p filep)) ; Local file without region + (append (bmkp-face-prop 'bmkp-local-file-without-region) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Jump to (visit) file `%s'" ,filep)))) + ; Existing buffer, including for a file bookmark if the file buffer has not yet been saved. + ((and buffp (get-buffer buffp)) + (append (bmkp-face-prop 'bmkp-buffer) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Jump to buffer `%s'" ,buffp)))) + ((or (not filep) (equal filep bmkp-non-file-filename)) ; Non-file, and no existing buffer. + (append (bmkp-face-prop 'bmkp-non-file) + `(mouse-face highlight follow-link t + help-echo (format "mouse-2: Create buffer `%s' and jump to it" ,buffp)))) + ((and filep (not (file-exists-p filep))) ; Local-file bookmark, but no such file exists. + (bmkp-face-prop 'bmkp-no-local)) + (t (append (bmkp-face-prop 'bmkp-bad-bookmark) + `(mouse-face highlight follow-link t + help-echo (format "BAD BOOKMARK (maybe): `%s'" ,filep)))))) + bookmark-name)) + +;;;###autoload (autoload 'bmkp-bmenu-quit "bookmark+") +(defun bmkp-bmenu-quit () ; Bound to `q' in bookmark list + "Quit the bookmark list (aka \"menu list\"). +If `bmkp-bmenu-state-file' is non-nil, then save the state, to be +restored the next time the bookmark list is shown. Otherwise, reset +the internal lists that record menu-list markings." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (if (not bmkp-bmenu-state-file) + (setq bmkp-bmenu-marked-bookmarks () + bmkp-bmenu-before-hide-marked-alist () + bmkp-bmenu-before-hide-unmarked-alist ()) + (when (interactive-p) (message "Saving bookmark-list display state...")) + (bmkp-save-menu-list-state) + (when (interactive-p) (message "Saving bookmark-list display state...done")) + (setq bmkp-bmenu-first-time-p t)) + (quit-window)) + +(defun bmkp-bmenu-goto-bookmark-named (name) + "Go to the first bookmark whose name matches NAME (a string). +If NAME has non-nil property `bmkp-full-record' then go to the +bookmark it indicates. Otherwise, just go to the first bookmark with +the same name." + (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (let ((full (get-text-property 0 'bmkp-full-record name))) + (while (and (not (eobp)) + (not (if full + (equal full (get-text-property 0 'bmkp-full-record (bookmark-bmenu-bookmark))) + (equal name (bookmark-bmenu-bookmark))))) + (forward-line 1))) + (bookmark-bmenu-ensure-position)) ; Just in case we fall off the end. + +;; This is a general function. It is in this file because it is used only by the bmenu code. +(defun bmkp-bmenu-barf-if-not-in-menu-list () + "Raise an error if current buffer is not `*Bookmark List*'." + (unless (derived-mode-p 'bookmark-bmenu-mode) + (error "You can only use this command in buffer `*Bookmark List*'"))) + +(defun bmkp-face-prop (value) + "Return a list with elements `face' or `font-lock-face' and VALUE. +Starting with Emacs 22, the first element is `font-lock-face'." + (list (if (> emacs-major-version 21) 'font-lock-face 'face) value)) + +(when (or (> emacs-major-version 24) ; Emacs bug #12867 was partially fixed for Emacs 24.3+. + (and (= emacs-major-version 24) (> emacs-minor-version 2))) + (defun bmkp-bmenu-mode-line-string () + "Show, in mode line, information about the current bookmark-list display. +The information includes the sort order and the number of marked, +flagged (for deletion), tagged, temporary, annotated, and modified +bookmarks currently shown. + +For each number indication: + If the current line has the indicator (e.g. mark, flag) and there are + others with the same indicator listed after it, then show `N/M', + where N is the number indicated through the current line and M is the + total number indicated." + (let* ((regexp-> "^>") + (regexp-D "^D") + (regexp-t "^.t") + (regexp-X "^..X") + (regexp-a "^..a") + (regexp-* "^...\\*") + (nb-> (count-matches regexp-> (point-min) (point-max))) + (nb-D (count-matches regexp-D (point-min) (point-max))) + (nb-t (count-matches regexp-t (point-min) (point-max))) + (nb-X (count-matches regexp-X (point-min) (point-max))) + (nb-a (count-matches regexp-a (point-min) (point-max))) + (nb-* (count-matches regexp-* (point-min) (point-max))) + (text-sort (propertize + (concat "sorting " (bmkp-sorting-description (bmkp-current-sort-order))) + 'face 'bmkp-heading)) + regexp) + (let ((desc "") + nb) + (dolist (mk '(?> ?D ?t ?a ?X ?*)) + (setq nb (symbol-value (intern (format "nb-%c" mk))) + regexp (symbol-value (intern (format "regexp-%c" mk))) + desc (concat + desc + (and (> nb 0) + (propertize + (format + "%s%d%c" + (save-excursion + (forward-line 0) + (if (bmkp-looking-at-p (concat regexp ".*")) + (format "%d/" (1+ (count-matches regexp (point-min) (point)))) + "")) + nb mk) + 'face (intern (format "bmkp-%c-mark" mk)))) + (and (> nb 0) " ")))) + (format "%s%s" desc text-sort)))) + + (defun bmkp-bmenu-mode-line () ; This works, but it shows the line number also. + "Set the mode line for buffer `*Bookmark List*'." + (condition-case nil + (progn + (set (make-local-variable 'mode-name) '(:eval (bmkp-bmenu-mode-line-string))) + ;; It seems that the line number must be present, and not invisible, for dynamic updating + ;; of the mode line when you move the cursor among lines. Moving it way off to the right + ;; effectively gets rid of it (ugly hack). See Emacs bug #12867. + (set (make-local-variable 'mode-line-position) '("%360l (line)")) ; Move it off the screen. + (set (make-local-variable 'mode-line-format) + '(("" mode-name "\t" mode-line-buffer-identification mode-line-position)))) + (error nil)))) + +(when (fboundp 'org-add-link-type) + (org-add-link-type "bookmark" 'bookmark-jump) + (org-add-link-type "bookmark-other-win" 'bookmark-jump-other-window) + (add-hook 'org-store-link-functions 'bmkp-bmenu-store-org-link 'APPEND) + (defun bmkp-bmenu-store-org-link () + "Store a link to this bookmark for insertion in an Org-mode buffer. +If you use a numeric prefix arg with `\\[org-store-link]' then the +bookmark will be jumped to in the same window. Without a numeric +prefix arg, the link will use another window. The link type is +`bookmark' or `bookmark-other-win', respectively." + (require 'org) + (and (derived-mode-p 'bookmark-bmenu-mode) + (let* ((other-win (and current-prefix-arg (not (consp current-prefix-arg)))) + (bmk (bookmark-bmenu-bookmark)) + (link (format "bookmark%s:%s" (if other-win "-other-win" "") bmk)) + (bmk-desc (format "Bookmark: %s" bmk))) + (org-store-link-props :type "bookmark" :link link :description bmk-desc))))) + + +;;(@* "Sorting - Commands") +;; *** Sorting - Commands *** + +;;;###autoload (autoload 'bmkp-bmenu-change-sort-order-repeat "bookmark+") +(defun bmkp-bmenu-change-sort-order-repeat (arg) ; Bound to `s s'... in bookmark list + "Cycle to the next sort order. +With a prefix arg, reverse current sort order. +This is a repeatable version of `bmkp-bmenu-change-sort-order'." + (interactive "P") + (require 'repeat) + (bmkp-repeat-command 'bmkp-bmenu-change-sort-order)) + +;;;###autoload (autoload 'bmkp-bmenu-change-sort-order "bookmark+") +(defun bmkp-bmenu-change-sort-order (&optional arg) + "Cycle to the next sort order. +With a prefix arg, reverse the current sort order." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-sort-orders-for-cycling-alist (delq nil bmkp-sort-orders-for-cycling-alist)) + (if arg + (bmkp-reverse-sort-order) + (let ((curr-bmk (bookmark-bmenu-bookmark)) + next-order) + (let ((orders (mapcar #'car bmkp-sort-orders-for-cycling-alist))) + (setq next-order (or (cadr (member (bmkp-current-sort-order) orders)) (car orders)) + bmkp-sort-comparer (cdr (assoc next-order bmkp-sort-orders-for-cycling-alist)))) + (message "Sorting...") + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk ; Put cursor back on the right line. + (bmkp-bmenu-goto-bookmark-named curr-bmk)) + (when (interactive-p) (bmkp-msg-about-sort-order next-order))))) + +;; This is a general command. It is in this file because it is used only by the bmenu code. +;;;###autoload (autoload 'bmkp-reverse-sort-order "bookmark+") +(defun bmkp-reverse-sort-order () ; Bound to `s r' in bookmark list + "Reverse the current bookmark sort order. +If you combine this with \\\ +`\\[bmkp-reverse-multi-sort-order]', then see the doc for that command." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-reverse-sort-p (not bmkp-reverse-sort-p)) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk ; Put cursor back on the right line. + (bmkp-bmenu-goto-bookmark-named curr-bmk))) + (when (interactive-p) (bmkp-msg-about-sort-order (bmkp-current-sort-order)))) + +;; This is a general command. It is in this file because it is used only by the bmenu code. +;;;###autoload (autoload 'bmkp-reverse-multi-sort-order "bookmark+") +(defun bmkp-reverse-multi-sort-order () ; Bound to `s C-r' in bookmark list + "Reverse the application of multi-sorting predicates. +These are the PRED predicates described for option +`bmkp-sort-comparer'. + +This reverses the order in which the predicates are tried, and it +also complements the truth value returned by each predicate. + +For example, if the list of multi-sorting predicates is (p1 p2 p3), +then the predicates are tried in the order: p3, p2, p1. And if a +predicate returns true, `(t)', then the effect is as if it returned +false, `(nil)', and vice versa. + +The use of multi-sorting predicates tends to group bookmarks, with the +first predicate corresponding to the first bookmark group etc. + +The effect of \\`\\[bmkp-reverse-multi-sort-order]' is \ +roughly as follows: + + - without also `\\[bmkp-reverse-sort-order]', it reverses the bookmark order in each \ +group + + - combined with `\\[bmkp-reverse-sort-order]', it reverses the order of the bookmark + groups, but not the bookmarks within a group + +This is a rough description. The actual behavior can be complex, +because of how each predicate is defined. If this description helps +you, fine. If not, just experiment and see what happens. \;-) + +Remember that ordinary `\\[bmkp-reverse-sort-order]' reversal on its own is \ +straightforward. +If you find `\\[bmkp-reverse-multi-sort-order]' confusing or not helpful, then do not \ +use it." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (setq bmkp-reverse-multi-sort-p (not bmkp-reverse-multi-sort-p)) + (let ((curr-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list 'NO-MSG-P) + (when curr-bmk ; Put cursor back on the right line. + (bmkp-bmenu-goto-bookmark-named curr-bmk))) + (when (interactive-p) (bmkp-msg-about-sort-order (bmkp-current-sort-order)))) + + + +;; The ORDER of the macro calls here defines the REVERSE ORDER of +;; `bmkp-sort-orders-alist'. The first here is thus also the DEFAULT sort order. +;; Entries are traversed by `s s'..., in `bmkp-sort-orders-alist' order. + +(bmkp-define-sort-command ; Bound to `s k' in bookmark list (`k' for "kind") + "by bookmark type" ; `bmkp-bmenu-sort-by-bookmark-type' + ((bmkp-info-node-name-cp bmkp-url-cp bmkp-gnus-cp bmkp-local-file-type-cp bmkp-handler-cp) + bmkp-alpha-p) + "Sort bookmarks by type: Info, URL, Gnus, files, other (by handler name).") + +(bmkp-define-sort-command ; Bound to `s u' in bookmark list + "by url" ; `bmkp-bmenu-sort-by-url' + ((bmkp-url-cp) bmkp-alpha-p) + "Sort URL bookmarks alphabetically by their URL/filename. +When two bookmarks are not comparable this way, compare them by +bookmark name.") + +;; $$$$$$ Not used now. +;; (bmkp-define-sort-command ; Bound to `s w 3' in bookmark list +;; "by W3M url" ; `bmkp-bmenu-sort-by-w3m-url' +;; ((bmkp-w3m-cp) bmkp-alpha-p) +;; "Sort W3M bookmarks alphabetically by their URL/filename. +;; When two bookmarks are not comparable this way, compare them by +;; bookmark name.") + +;; (when (fboundp 'bmkp-eww-cp) +;; ;; $$$$$$ Not used now. +;; ;; (bmkp-define-sort-command ; Bound to `s w e' in bookmark list +;; ;; "by EWW url" ; `bmkp-bmenu-sort-by-w3m-url' +;; ;; ((bmkp-eww-cp) bmkp-alpha-p) +;; ;; "Sort EWW bookmarks alphabetically by their URL/filename. +;; ;; When two bookmarks are not comparable this way, compare them by +;; ;; bookmark name.") +;; ) + +(bmkp-define-sort-command ; Bound to `s g' in bookmark list + "by Gnus thread" ; `bmkp-bmenu-sort-by-Gnus-thread' + ((bmkp-gnus-cp) bmkp-alpha-p) + "Sort Gnus bookmarks by group, then by article, then by message. +When two bookmarks are not comparable this way, compare them by +bookmark name.") + +(bmkp-define-sort-command ; Bound to `s i' in bookmark list + "by Info node name" ; `bmkp-bmenu-sort-by-Info-node-name' + ((bmkp-info-node-name-cp) bmkp-alpha-p) + "Sort Info bookmarks by manual (file) name, then node name, then position. +When two bookmarks are not comparable this way, compare them by +bookmark name.") + +(bmkp-define-sort-command ; Bound to `s I' in bookmark list + "by Info position" ; `bmkp-bmenu-sort-by-Info-position' + ((bmkp-info-position-cp) bmkp-alpha-p) + "Sort Info bookmarks by manual (file) name, then position (order in book). +When two bookmarks are not comparable this way, compare them by +bookmark name.") + +(bmkp-define-sort-command ; Bound to `s f u' in bookmark list + "by last local file update" ; `bmkp-bmenu-sort-by-last-local-file-update' + ((bmkp-local-file-updated-more-recently-cp) bmkp-alpha-p) + "Sort bookmarks by last local file update time. +Sort a local file before a remote file, and a remote file before other +bookmarks. Otherwise, sort by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s f d' in bookmark list + "by last local file access" ; `bmkp-bmenu-sort-by-last-local-file-access' + ((bmkp-local-file-accessed-more-recently-cp) bmkp-alpha-p) + "Sort bookmarks by last local file access time. +A local file sorts before a remote file, which sorts before other +bookmarks. Otherwise, sort by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s f s' in bookmark list + "by local file size" ; `bmkp-bmenu-sort-by-local-file-size' + ((bmkp-local-file-size-cp) bmkp-alpha-p) + "Sort bookmarks by local file size. +A local file sorts before a remote file, which sorts before other +bookmarks. Otherwise, sort by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s f n' in bookmark list + "by file name" ; `bmkp-bmenu-sort-by-file-name' + ((bmkp-file-alpha-cp) bmkp-alpha-p) + "Sort bookmarks by file name. +When two bookmarks are not comparable by file name, compare them by +bookmark name.") + +(bmkp-define-sort-command ; Bound to `s f k' in bookmark list (`k' for "kind") + "by local file type" ; `bmkp-bmenu-sort-by-local-file-type' + ((bmkp-local-file-type-cp) bmkp-alpha-p) + "Sort bookmarks by local file type: file, symlink, directory. +A local file sorts before a remote file, which sorts before other +bookmarks. Otherwise, sort by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s D' in bookmark list + "flagged before unflagged" ; `bmkp-bmenu-sort-flagged-before-unflagged' + ((bmkp-flagged-cp) bmkp-alpha-p) + "Sort bookmarks by putting flagged for deletion before unflagged. +Otherwise alphabetize by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s *' in bookmark list + "modified before unmodified" ; `bmkp-bmenu-sort-modified-before-unmodified' + ((bmkp-modified-cp) bmkp-alpha-p) + "Sort bookmarks by putting modified before unmodified (saved). +Otherwise alphabetize by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s >' in bookmark list + "marked before unmarked" ; `bmkp-bmenu-sort-marked-before-unmarked' + ((bmkp-marked-cp) bmkp-alpha-p) + "Sort bookmarks by putting marked before unmarked. +Otherwise alphabetize by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s 0' (zero) in bookmark list + "by creation time" ; `bmkp-bmenu-sort-by-creation-time' + ((bmkp-bookmark-creation-cp) bmkp-alpha-p) + "Sort bookmarks by the time of their creation. +When one or both of the bookmarks does not have a `created' entry), +compare them by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s a' in bookmark list + "annotated before unannotated" ; `bmkp-bmenu-sort-annotated-before-unannotated' + ((bmkp-annotated-cp) bmkp-alpha-p) + "Sort bookmarks by putting annotated before unannotated. +Otherwise alphabetize by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s b' in bookmark list + "by last buffer or file access" ; `bmkp-bmenu-sort-by-last-buffer-or-file-access' + ((bmkp-buffer-last-access-cp bmkp-local-file-accessed-more-recently-cp) + bmkp-alpha-p) + "Sort bookmarks by last buffer access or last local file access. +Sort a bookmark accessed more recently before one accessed less +recently or not accessed. Sort a bookmark to an existing buffer +before a local file bookmark. When two bookmarks are not comparable +by such critera, sort them by bookmark name. (In particular, sort +remote-file bookmarks by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s v' in bookmark list + "by bookmark visit frequency" ; `bmkp-bmenu-sort-by-bookmark-visit-frequency' + ((bmkp-visited-more-cp) bmkp-alpha-p) + "Sort bookmarks by the number of times they were visited as bookmarks. +When two bookmarks are not comparable by visit frequency, compare them +by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s d' in bookmark list + "by last bookmark access" ; `bmkp-bmenu-sort-by-last-bookmark-access' + ((bmkp-bookmark-last-access-cp) bmkp-alpha-p) + "Sort bookmarks by the time of their last visit as bookmarks. +When two bookmarks are not comparable by visit time, compare them +by bookmark name.") + +(bmkp-define-sort-command ; Bound to `s n' in bookmark list + "by bookmark name" ; `bmkp-bmenu-sort-by-bookmark-name' + bmkp-alpha-p + "Sort bookmarks by bookmark name, respecting `case-fold-search'.") + +(bmkp-define-sort-command ; Bound to `s t' in bookmark list + "tagged before untagged" ; `bmkp-bmenu-sort-tagged-before-untagged' + ((bmkp-tagged-cp) bmkp-alpha-p) + "Sort bookmarks by putting tagged before untagged. +Otherwise alphabetize by bookmark name.") + +;; This is a general option. It is in this file because it is used mainly by the bmenu code. +;; Its definitions MUST COME AFTER the calls to macro `bmkp-define-sort-command'. +;; Otherwise, they won't pick up a populated `bmkp-sort-orders-alist'. +(when (> emacs-major-version 20) + (defcustom bmkp-sort-orders-for-cycling-alist (copy-sequence bmkp-sort-orders-alist) + "*Alist of sort orders used for cycling via `s s'... +This is a subset of the complete list of available sort orders, +`bmkp-sort-orders-alist'. This lets you cycle among fewer sort +orders, if there are some that you do not use often. + +See the doc for `bmkp-sort-orders-alist', for the structure of +this value." + :type '(alist + :key-type (choice :tag "Sort order" string symbol) + :value-type (choice + (const :tag "None (do not sort)" nil) + (function :tag "Sorting Predicate") + (list :tag "Sorting Multi-Predicate" + (repeat (function :tag "Component Predicate")) + (choice + (const :tag "None" nil) + (function :tag "Final Predicate"))))) + :group 'bookmark-plus)) + +(unless (> emacs-major-version 20) ; Emacs 20: custom type `alist' doesn't exist. + (defcustom bmkp-sort-orders-for-cycling-alist (copy-sequence bmkp-sort-orders-alist) + "*Alist of sort orders used for cycling via `s s'... +This is a subset of the complete list of available sort orders, +`bmkp-sort-orders-alist'. This lets you cycle among fewer sort +orders, if there are some that you do not use often. + +See the doc for `bmkp-sort-orders-alist', for the structure of this +value." + :type '(repeat + (cons + (choice :tag "Sort order" string symbol) + (choice + (const :tag "None (do not sort)" nil) + (function :tag "Sorting Predicate") + (list :tag "Sorting Multi-Predicate" + (repeat (function :tag "Component Predicate")) + (choice + (const :tag "None" nil) + (function :tag "Final Predicate")))))) + :group 'bookmark-plus)) + + +;;(@* "Other Bookmark+ Functions (`bmkp-*')") +;; *** Other Bookmark+ Functions (`bmkp-*') *** + +;;;###autoload (autoload 'bmkp-bmenu-show-this-annotation+move-down "bookmark+") +(defun bmkp-bmenu-show-this-annotation+move-down (&optional n) ; Bound to `M-down' in bookmark list + "Move down N lines in bookmark-list display and show annotation, if any." + (interactive "p") + (bmkp-bmenu-kill-annotation) + (forward-line n) + (bookmark-bmenu-show-annotation 'MSGP)) + +;;;###autoload (autoload 'bmkp-bmenu-show-this-annotation+move-up "bookmark+") +(defun bmkp-bmenu-show-this-annotation+move-up (&optional n) ; Bound to `M-up' in bookmark list + "Move up N lines in bookmark-list display and show annotation, if any." + (interactive "p") + (bmkp-bmenu-kill-annotation) + (forward-line (- n)) + (bookmark-bmenu-show-annotation 'MSGP)) + +(defun bmkp-bmenu-kill-annotation (&optional bookmark-name) + "Kill annotation buffer, if any, for BOOKMARK-NAME. +If BOOKMARK-NAME is nil, use the bookmark of the current line. +Return non-nil only if there was such an annotation buffer." + (let ((ann-buf (get-buffer (format "*`%s' Annotation*" + (or bookmark-name (bookmark-bmenu-bookmark)))))) + (when ann-buf (kill-buffer ann-buf)))) + +;;;###autoload (autoload 'bmkp-bmenu-describe-this+move-down "bookmark+") +(defun bmkp-bmenu-describe-this+move-down (&optional defn) ; Bound to `C-down' in bookmark list + "Move to next line in bookmark-list display and describe the bookmark. +With a prefix argument, show the internal definition of the bookmark." + (interactive "P") + (forward-line 1) + (bmkp-bmenu-describe-this-bookmark)) + +;;;###autoload (autoload 'bmkp-bmenu-describe-this+move-up "bookmark+") +(defun bmkp-bmenu-describe-this+move-up (&optional defn) ; Bound to `C-up' in bookmark list + "Move to previous line in bookmark-list display and describe the bookmark. +With a prefix argument, show the internal definition of the bookmark." + (interactive "P") + (forward-line -1) + (bmkp-bmenu-describe-this-bookmark)) + +;;;###autoload (autoload 'bmkp-bmenu-describe-this-bookmark "bookmark+") +(defun bmkp-bmenu-describe-this-bookmark (&optional defn) ; Bound to `C-h RET' in bookmark list + "Describe bookmark of current line. +With a prefix argument, show the internal definition of the bookmark." + (interactive "P") + (bmkp-bmenu-barf-if-not-in-menu-list) + (save-selected-window (if defn + (bmkp-describe-bookmark-internals (bookmark-bmenu-bookmark)) + (bmkp-describe-bookmark (bookmark-bmenu-bookmark))))) + +;;;###autoload (autoload 'bmkp-bmenu-describe-marked "bookmark+") +(defun bmkp-bmenu-describe-marked (&optional defn include-omitted-p) ; Bound to `C-h >' in bookmark list + "Describe the marked bookmarks, in the current sort order. +If no bookmark is marked, act on the bookmark of the current line. + +With a non-negative prefix argument, show the internal definitions. + +Omitted bookmarks are excluded, by default. With a non-positive +prefix arg, any that are marked are included." + (interactive (list (and current-prefix-arg (>= (prefix-numeric-value current-prefix-arg) 0)) + (and current-prefix-arg (<= (prefix-numeric-value current-prefix-arg) 0)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (help-setup-xref (list #'bmkp-bmenu-describe-marked) (interactive-p)) + (bmkp-with-help-window "*Help*" + (dolist (bmk (bmkp-sort-omit (bmkp-bmenu-marked-or-this-or-all nil include-omitted-p))) + (if defn + (let* ((bname (bmkp-bookmark-name-from-record bmk)) + (print-circle bmkp-propertize-bookmark-names-flag) ; For `pp-to-string' + (print-gensym bmkp-propertize-bookmark-names-flag) ; For `pp-to-string' + (print-length nil) ; For `pp-to-string' + (print-level nil) ; For `pp-to-string' + (help-text (format "%s\n%s\n\n%s" + bname (make-string (length bname) ?-) (pp-to-string bmk)))) + (princ help-text) (terpri)) + (princ (bmkp-bookmark-description bmk)) (terpri))))) + +(defun bmkp-bmenu-get-marked-files () + "Return a list of the file names of the marked bookmarks. +Marked bookmarks that have no associated file are ignored." + (let ((files ())) + (dolist (bmk bmkp-bmenu-marked-bookmarks) + (when (bmkp-file-bookmark-p bmk) (push (bookmark-get-filename bmk) files))) + files)) + +(defun bmkp-bmenu-marked-or-this-or-all (&optional allp include-omitted-p) + "Return the marked bookmarks or the current-line bookmark if none marked. +Non-nil ALLP means return all bookmarks: `bookmark-alist'. +Do not include marked bookmarks that are omitted, unless optional arg +INCLUDE-OMITTED-P is non-nil. INCLUDE-OMITTED-P has no effect if none +are marked or ALLP is non-nil." + (if allp + bookmark-alist + (or (if include-omitted-p + (bmkp-marked-bookmarks-only) + (bmkp-remove-if #'bmkp-omitted-bookmark-p (bmkp-marked-bookmarks-only))) + (and (bookmark-bmenu-bookmark) (list (bmkp-get-bookmark (bookmark-bmenu-bookmark))))))) + +;;(@* "Keymaps") +;;; Keymaps ---------------------------------------------------------- + +;; `bookmark-bmenu-mode-map' + +(when (< emacs-major-version 21) + (define-key bookmark-bmenu-mode-map (kbd "RET") 'bookmark-bmenu-this-window)) +(define-key bookmark-bmenu-mode-map "\M-~" 'bmkp-toggle-saving-bookmark-file) +(define-key bookmark-bmenu-mode-map (kbd "C-M-~") 'bmkp-toggle-saving-menu-list-state) +(define-key bookmark-bmenu-mode-map "." 'bmkp-bmenu-show-all) +(define-key bookmark-bmenu-mode-map ">" 'bmkp-bmenu-toggle-show-only-marked) +(define-key bookmark-bmenu-mode-map "<" 'bmkp-bmenu-toggle-show-only-unmarked) +(define-key bookmark-bmenu-mode-map (kbd "M-") 'bmkp-bmenu-unmark-all) +(define-key bookmark-bmenu-mode-map "-" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "->" 'bmkp-bmenu-omit/unomit-marked) +(define-key bookmark-bmenu-mode-map "-S" 'bmkp-bmenu-show-only-omitted-bookmarks) +(define-key bookmark-bmenu-mode-map "-U" 'bmkp-unomit-all) +(define-key bookmark-bmenu-mode-map "=" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "=bM" 'bmkp-bmenu-mark-specific-buffer-bookmarks) +(define-key bookmark-bmenu-mode-map "=fM" 'bmkp-bmenu-mark-specific-file-bookmarks) +(define-key bookmark-bmenu-mode-map "=bS" 'bmkp-bmenu-show-only-specific-buffer-bookmarks) +(define-key bookmark-bmenu-mode-map "=fS" 'bmkp-bmenu-show-only-specific-file-bookmarks) +(define-key bookmark-bmenu-mode-map "%" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "%m" 'bmkp-bmenu-regexp-mark) +(define-key bookmark-bmenu-mode-map "*" nil) ; For Emacs 20 +(when (< emacs-major-version 21) + (define-key bookmark-bmenu-mode-map "*m" 'bookmark-bmenu-mark)) +(define-key bookmark-bmenu-mode-map "#" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "#M" 'bmkp-bmenu-mark-autonamed-bookmarks) +(define-key bookmark-bmenu-mode-map "#S" 'bmkp-bmenu-show-only-autonamed-bookmarks) +;; `a' is `bookmark-bmenu-show-annotation' in vanilla Emacs. +;; `A' is `bookmark-bmenu-show-all-annotations' in vanilla Emacs. +;; `e' is `bookmark-bmenu-edit-annotation' in vanilla Emacs. +(define-key bookmark-bmenu-mode-map "a" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "aa" 'bookmark-bmenu-show-annotation) +(define-key bookmark-bmenu-mode-map "aA" 'bookmark-bmenu-show-all-annotations) +(define-key bookmark-bmenu-mode-map "ae" 'bookmark-bmenu-edit-annotation) +(define-key bookmark-bmenu-mode-map "a>" 'bmkp-bmenu-edit-annotations-for-marked) +(define-key bookmark-bmenu-mode-map "A" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "AM" 'bmkp-bmenu-mark-autofile-bookmarks) +(define-key bookmark-bmenu-mode-map "AS" 'bmkp-bmenu-show-only-autofile-bookmarks) +(define-key bookmark-bmenu-mode-map "B" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "BM" 'bmkp-bmenu-mark-non-file-bookmarks) +(define-key bookmark-bmenu-mode-map "BS" 'bmkp-bmenu-show-only-non-file-bookmarks) +(define-key bookmark-bmenu-mode-map (kbd "M-n") 'bmkp-bmenu-clone-bookmark) +(define-key bookmark-bmenu-mode-map (kbd "C-c C-c") 'bmkp-bmenu-define-command) +(define-key bookmark-bmenu-mode-map (kbd "C-c C-S-c") 'bmkp-bmenu-define-full-snapshot-command) +(define-key bookmark-bmenu-mode-map (kbd "C-c C-j") 'bmkp-bmenu-define-jump-marked-command) +(define-key bookmark-bmenu-mode-map "d" 'bmkp-bmenu-flag-for-deletion) +(define-key bookmark-bmenu-mode-map "D" 'bmkp-bmenu-delete-marked) +(define-key bookmark-bmenu-mode-map "\C-d" 'bmkp-bmenu-flag-for-deletion-backwards) +(define-key bookmark-bmenu-mode-map "\M-d" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "\M-d>" 'bmkp-bmenu-dired-marked) +(define-key bookmark-bmenu-mode-map "\M-d\M-m" 'bmkp-bmenu-mark-dired-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-d\M-s" 'bmkp-bmenu-show-only-dired-bookmarks) +;; `e' is `bookmark-bmenu-edit-annotation' in vanilla Emacs. +(define-key bookmark-bmenu-mode-map "e" 'bmkp-bmenu-edit-bookmark-record) +(define-key bookmark-bmenu-mode-map "E" 'bmkp-bmenu-edit-marked) +(define-key bookmark-bmenu-mode-map "F" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "FM" 'bmkp-bmenu-mark-file-bookmarks) +(define-key bookmark-bmenu-mode-map "FS" 'bmkp-bmenu-show-only-file-bookmarks) +(define-key bookmark-bmenu-mode-map "g" 'bmkp-bmenu-refresh-menu-list) +(define-key bookmark-bmenu-mode-map "G" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "GM" 'bmkp-bmenu-mark-gnus-bookmarks) +(define-key bookmark-bmenu-mode-map "GS" 'bmkp-bmenu-show-only-gnus-bookmarks) +(if (fboundp 'command-remapping) + (define-key bookmark-bmenu-mode-map [remap describe-mode] 'bmkp-bmenu-mode-status-help) + ;; In Emacs < 22, the `substitute-...' affects only `?', not `C-h m', so we add it separately. + (substitute-key-definition 'describe-mode 'bmkp-bmenu-mode-status-help bookmark-bmenu-mode-map) + (define-key bookmark-bmenu-mode-map "\C-hm" 'bmkp-bmenu-mode-status-help)) +(define-key bookmark-bmenu-mode-map (kbd "C-h >") 'bmkp-bmenu-describe-marked) +(define-key bookmark-bmenu-mode-map (kbd "C-h RET") 'bmkp-bmenu-describe-this-bookmark) +(define-key bookmark-bmenu-mode-map (kbd "C-h C-") 'bmkp-bmenu-describe-this-bookmark) +(define-key bookmark-bmenu-mode-map (kbd "C-") 'bmkp-bmenu-describe-this+move-down) +(define-key bookmark-bmenu-mode-map (kbd "C-") 'bmkp-bmenu-describe-this+move-up) +(define-key bookmark-bmenu-mode-map (kbd "M-") 'bmkp-bmenu-show-this-annotation+move-down) +(define-key bookmark-bmenu-mode-map (kbd "M-") 'bmkp-bmenu-show-this-annotation+move-up) +(define-key bookmark-bmenu-mode-map (kbd "M-") 'bmkp-bmenu-w32-open) +(define-key bookmark-bmenu-mode-map [M-mouse-2] 'bmkp-bmenu-w32-open-with-mouse) +(when (featurep 'bookmark+-lit) + (define-key bookmark-bmenu-mode-map "H" nil) ; For Emacs 20 + (define-key bookmark-bmenu-mode-map "H+" 'bmkp-bmenu-set-lighting) + (define-key bookmark-bmenu-mode-map "H>+" 'bmkp-bmenu-set-lighting-for-marked) + (define-key bookmark-bmenu-mode-map "H>H" 'bmkp-bmenu-light-marked) + (define-key bookmark-bmenu-mode-map "HH" 'bmkp-bmenu-light) + (define-key bookmark-bmenu-mode-map "HM" 'bmkp-bmenu-mark-lighted-bookmarks) + (define-key bookmark-bmenu-mode-map "HS" 'bmkp-bmenu-show-only-lighted-bookmarks) + (define-key bookmark-bmenu-mode-map "H>U" 'bmkp-bmenu-unlight-marked) + (define-key bookmark-bmenu-mode-map "HU" 'bmkp-bmenu-unlight)) +(define-key bookmark-bmenu-mode-map "i" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "iM" 'bmkp-bmenu-mark-icicles-search-hits-bookmarks) +(define-key bookmark-bmenu-mode-map "iS" 'bmkp-bmenu-show-only-icicles-search-hits-bookmarks) +(define-key bookmark-bmenu-mode-map "I" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "IM" 'bmkp-bmenu-mark-info-bookmarks) +(define-key bookmark-bmenu-mode-map "IS" 'bmkp-bmenu-show-only-info-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-I" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "\M-I\M-M" 'bmkp-bmenu-mark-image-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-I\M-S" 'bmkp-bmenu-show-only-image-bookmarks) + +;; Prefix `j' and `J' bindings are made in `bookmark+-key.el', by binding `bmkp-jump(-other-window)-map'. + +(define-key bookmark-bmenu-mode-map "k" 'bmkp-bmenu-flag-for-deletion) +(define-key bookmark-bmenu-mode-map "K" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "KM" 'bmkp-bmenu-mark-desktop-bookmarks) +(define-key bookmark-bmenu-mode-map "KS" 'bmkp-bmenu-show-only-desktop-bookmarks) +(define-key bookmark-bmenu-mode-map "L" 'bmkp-switch-bookmark-file-create) +(define-key bookmark-bmenu-mode-map [(control shift ?l)] 'bookmark-bmenu-locate) ; `C-L' (aka `C-S-l') +(define-key bookmark-bmenu-mode-map "\M-l" 'bmkp-bmenu-load-marked-bookmark-file-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-L" 'bmkp-temporary-bookmarking-mode) +(define-key bookmark-bmenu-mode-map "M" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "MM" 'bmkp-bmenu-mark-man-bookmarks) +(define-key bookmark-bmenu-mode-map "MS" 'bmkp-bmenu-show-only-man-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-m" 'bmkp-bmenu-mark-all) +(define-key bookmark-bmenu-mode-map "N" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "NM" 'bmkp-bmenu-mark-non-invokable-bookmarks) +(define-key bookmark-bmenu-mode-map "NS" 'bmkp-bmenu-show-only-non-invokable-bookmarks) +(define-key bookmark-bmenu-mode-map "O" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "OM" 'bmkp-bmenu-mark-orphaned-local-file-bookmarks) +(define-key bookmark-bmenu-mode-map "OS" 'bmkp-bmenu-show-only-orphaned-local-file-bookmarks) +(define-key bookmark-bmenu-mode-map "P" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "PA" 'bmkp-bmenu-filter-annotation-incrementally) +(define-key bookmark-bmenu-mode-map "PB" 'bmkp-bmenu-filter-bookmark-name-incrementally) +(define-key bookmark-bmenu-mode-map "PF" 'bmkp-bmenu-filter-file-name-incrementally) +(define-key bookmark-bmenu-mode-map "PT" 'bmkp-bmenu-filter-tags-incrementally) +(define-key bookmark-bmenu-mode-map "q" 'bmkp-bmenu-quit) +(define-key bookmark-bmenu-mode-map "\M-q" 'bmkp-bmenu-query-replace-marked-bookmarks-regexp) +(define-key bookmark-bmenu-mode-map "Q" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "QM" 'bmkp-bmenu-mark-function-bookmarks) +(define-key bookmark-bmenu-mode-map "QS" 'bmkp-bmenu-show-only-function-bookmarks) +(define-key bookmark-bmenu-mode-map "r" 'bmkp-bmenu-edit-bookmark-name-and-location) +(define-key bookmark-bmenu-mode-map "R" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "RM" 'bmkp-bmenu-mark-region-bookmarks) +(define-key bookmark-bmenu-mode-map "RS" 'bmkp-bmenu-show-only-region-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-r" 'bookmark-bmenu-relocate) ; `R' in Emacs +(define-key bookmark-bmenu-mode-map "\M-R" 'bmkp-bmenu-relocate-marked) +(define-key bookmark-bmenu-mode-map "S" 'bookmark-bmenu-save) ; `s' in Emacs +(define-key bookmark-bmenu-mode-map "s" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "s>" 'bmkp-bmenu-sort-marked-before-unmarked) +(define-key bookmark-bmenu-mode-map "s*" 'bmkp-bmenu-sort-modified-before-unmodified) +(define-key bookmark-bmenu-mode-map "s0" 'bmkp-bmenu-sort-by-creation-time) +(define-key bookmark-bmenu-mode-map "sa" 'bmkp-bmenu-sort-annotated-before-unannotated) +(define-key bookmark-bmenu-mode-map "sb" 'bmkp-bmenu-sort-by-last-buffer-or-file-access) +(define-key bookmark-bmenu-mode-map "sd" 'bmkp-bmenu-sort-by-last-bookmark-access) +(define-key bookmark-bmenu-mode-map "sD" 'bmkp-bmenu-sort-flagged-before-unflagged) +(define-key bookmark-bmenu-mode-map "sfd" 'bmkp-bmenu-sort-by-last-local-file-access) +(define-key bookmark-bmenu-mode-map "sfk" 'bmkp-bmenu-sort-by-local-file-type) +(define-key bookmark-bmenu-mode-map "sfn" 'bmkp-bmenu-sort-by-file-name) +(define-key bookmark-bmenu-mode-map "sfs" 'bmkp-bmenu-sort-by-local-file-size) +(define-key bookmark-bmenu-mode-map "sfu" 'bmkp-bmenu-sort-by-last-local-file-update) +(define-key bookmark-bmenu-mode-map "sg" 'bmkp-bmenu-sort-by-Gnus-thread) +(define-key bookmark-bmenu-mode-map "si" 'bmkp-bmenu-sort-by-Info-node-name) +(define-key bookmark-bmenu-mode-map "sI" 'bmkp-bmenu-sort-by-Info-position) +(define-key bookmark-bmenu-mode-map "sk" 'bmkp-bmenu-sort-by-bookmark-type) +(define-key bookmark-bmenu-mode-map "sn" 'bmkp-bmenu-sort-by-bookmark-name) +(define-key bookmark-bmenu-mode-map "sr" 'bmkp-reverse-sort-order) +(define-key bookmark-bmenu-mode-map "s\C-r" 'bmkp-reverse-multi-sort-order) +(define-key bookmark-bmenu-mode-map "ss" 'bmkp-bmenu-change-sort-order-repeat) +(define-key bookmark-bmenu-mode-map "st" 'bmkp-bmenu-sort-tagged-before-untagged) +(define-key bookmark-bmenu-mode-map "su" 'bmkp-bmenu-sort-by-url) +(define-key bookmark-bmenu-mode-map "sv" 'bmkp-bmenu-sort-by-bookmark-visit-frequency) + +;; Not done yet. +;; ;; (define-key bookmark-bmenu-mode-map "sw" nil) ; For Emacs20 +;; ;; (define-key bookmark-bmenu-mode-map "swe" 'bmkp-bmenu-sort-by-eww-url) +;; ;; (define-key bookmark-bmenu-mode-map "sw3" 'bmkp-bmenu-sort-by-w3m-url) + +(when (> emacs-major-version 22) ; Emacs 23+ + (define-key bookmark-bmenu-mode-map (kbd "M-s a C-s") 'bmkp-bmenu-isearch-marked-bookmarks) + (define-key bookmark-bmenu-mode-map (kbd "M-s a M-C-s") 'bmkp-bmenu-isearch-marked-bookmarks-regexp)) +(define-key bookmark-bmenu-mode-map (kbd "M-s a M-s") 'bmkp-bmenu-search-marked-bookmarks-regexp) +(define-key bookmark-bmenu-mode-map "T" nil) ; For Emacs20 +(define-key bookmark-bmenu-mode-map "T>+" 'bmkp-bmenu-add-tags-to-marked) +(define-key bookmark-bmenu-mode-map "T>-" 'bmkp-bmenu-remove-tags-from-marked) +(define-key bookmark-bmenu-mode-map "T>e" 'bmkp-bmenu-edit-marked) +(define-key bookmark-bmenu-mode-map "T>l" 'bmkp-bmenu-list-tags-of-marked) +(define-key bookmark-bmenu-mode-map "T>p" 'bmkp-bmenu-paste-add-tags-to-marked) +(define-key bookmark-bmenu-mode-map "T>q" 'bmkp-bmenu-paste-replace-tags-for-marked) +(define-key bookmark-bmenu-mode-map "T>v" 'bmkp-bmenu-set-tag-value-for-marked) +(define-key bookmark-bmenu-mode-map "T>\C-y" 'bmkp-bmenu-paste-add-tags-to-marked) +(define-key bookmark-bmenu-mode-map "T0" 'bmkp-remove-all-tags) +(define-key bookmark-bmenu-mode-map "T+" 'bmkp-add-tags) +(define-key bookmark-bmenu-mode-map "T-" 'bmkp-remove-tags) +(define-key bookmark-bmenu-mode-map "Tc" 'bmkp-bmenu-copy-tags) +(define-key bookmark-bmenu-mode-map "Td" 'bmkp-remove-tags-from-all) +(define-key bookmark-bmenu-mode-map "Te" 'bmkp-bmenu-edit-tags) +(define-key bookmark-bmenu-mode-map "Tl" 'bmkp-list-all-tags) +(define-key bookmark-bmenu-mode-map "Tm*" 'bmkp-bmenu-mark-bookmarks-tagged-all) +(define-key bookmark-bmenu-mode-map "Tm%" 'bmkp-bmenu-mark-bookmarks-tagged-regexp) +(define-key bookmark-bmenu-mode-map "Tm+" 'bmkp-bmenu-mark-bookmarks-tagged-some) +(define-key bookmark-bmenu-mode-map "Tm~*" 'bmkp-bmenu-mark-bookmarks-tagged-not-all) +(define-key bookmark-bmenu-mode-map "Tm~+" 'bmkp-bmenu-mark-bookmarks-tagged-none) +(define-key bookmark-bmenu-mode-map "Tp" 'bmkp-bmenu-paste-add-tags) +(define-key bookmark-bmenu-mode-map "Tq" 'bmkp-bmenu-paste-replace-tags) +(define-key bookmark-bmenu-mode-map "Tr" 'bmkp-rename-tag) +(define-key bookmark-bmenu-mode-map "Ts" 'bmkp-define-tags-sort-command) +(define-key bookmark-bmenu-mode-map "TS" 'bmkp-bmenu-show-only-tagged-bookmarks) +(define-key bookmark-bmenu-mode-map "TU" 'bmkp-bmenu-show-only-untagged-bookmarks) +(define-key bookmark-bmenu-mode-map "Tu*" 'bmkp-bmenu-unmark-bookmarks-tagged-all) +(define-key bookmark-bmenu-mode-map "Tu%" 'bmkp-bmenu-unmark-bookmarks-tagged-regexp) +(define-key bookmark-bmenu-mode-map "Tu+" 'bmkp-bmenu-unmark-bookmarks-tagged-some) +(define-key bookmark-bmenu-mode-map "Tu~*" 'bmkp-bmenu-unmark-bookmarks-tagged-not-all) +(define-key bookmark-bmenu-mode-map "Tu~+" 'bmkp-bmenu-unmark-bookmarks-tagged-none) +(define-key bookmark-bmenu-mode-map "Tv" 'bmkp-bmenu-set-tag-value) +(define-key bookmark-bmenu-mode-map "T\M-w" 'bmkp-bmenu-copy-tags) +(define-key bookmark-bmenu-mode-map "T\C-y" 'bmkp-bmenu-paste-add-tags) +(define-key bookmark-bmenu-mode-map "\M-t" 'bookmark-bmenu-toggle-filenames) ; `t' in Emacs +(define-key bookmark-bmenu-mode-map "t" 'bmkp-bmenu-toggle-marks) +(define-key bookmark-bmenu-mode-map "U" 'bmkp-bmenu-unmark-all) +(define-key bookmark-bmenu-mode-map "\M-u" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "\M-u\M-m" 'bmkp-bmenu-mark-url-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-u\M-s" 'bmkp-bmenu-show-only-url-bookmarks) +(define-key bookmark-bmenu-mode-map "v" 'bmkp-bmenu-w32-jump-to-marked) +(define-key bookmark-bmenu-mode-map "V" nil) ; For Emacs20 +(define-key bookmark-bmenu-mode-map "VM" 'bmkp-bmenu-mark-variable-list-bookmarks) +(define-key bookmark-bmenu-mode-map "VS" 'bmkp-bmenu-show-only-variable-list-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-o" 'bmkp-bmenu-w32-jump-to-marked) +(define-key bookmark-bmenu-mode-map "W" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "W3" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "W3M" 'bmkp-bmenu-mark-w3m-bookmarks) +(define-key bookmark-bmenu-mode-map "W3S" 'bmkp-bmenu-show-only-w3m-bookmarks) + +(when (fboundp 'bmkp-bmenu-mark-eww-bookmarks) ; Emacs 25+ + (define-key bookmark-bmenu-mode-map "WEM" 'bmkp-bmenu-mark-eww-bookmarks) + (define-key bookmark-bmenu-mode-map "WES" 'bmkp-bmenu-show-only-eww-bookmarks) + ) +(define-key bookmark-bmenu-mode-map "w" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "wM" 'bmkp-bmenu-mark-snippet-bookmarks) +(define-key bookmark-bmenu-mode-map "wS" 'bmkp-bmenu-show-only-snippet-bookmarks) +(define-key bookmark-bmenu-mode-map "X" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "XM" 'bmkp-bmenu-mark-temporary-bookmarks) +(define-key bookmark-bmenu-mode-map "XS" 'bmkp-bmenu-show-only-temporary-bookmarks) +(define-key bookmark-bmenu-mode-map "\M-X" 'bmkp-bmenu-toggle-marked-temporary/savable) +(define-key bookmark-bmenu-mode-map "\C-\M-X" 'bmkp-bmenu-toggle-temporary) +(define-key bookmark-bmenu-mode-map "Y" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "YM" 'bmkp-bmenu-mark-bookmark-file-bookmarks) +(define-key bookmark-bmenu-mode-map "YS" 'bmkp-bmenu-show-only-bookmark-file-bookmarks) +(define-key bookmark-bmenu-mode-map "Y>" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "Y>+" 'bmkp-bmenu-copy-marked-to-bookmark-file) +(define-key bookmark-bmenu-mode-map "Y>-" 'bmkp-bmenu-move-marked-to-bookmark-file) +(define-key bookmark-bmenu-mode-map "Y>0" 'bmkp-bmenu-create-bookmark-file-from-marked) +(define-key bookmark-bmenu-mode-map "Z" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "ZM" 'bmkp-bmenu-mark-bookmark-list-bookmarks) +(define-key bookmark-bmenu-mode-map "ZS" 'bmkp-bmenu-show-only-bookmark-list-bookmarks) + + +;;; `Bookmark+' menu-bar menu in `*Bookmark List*' + +(defvar bmkp-bmenu-menubar-menu (make-sparse-keymap "Bookmark+") "`Boomark+' menu-bar menu.") +(define-key bookmark-bmenu-mode-map [menu-bar bmkp] + (cons "Bookmark+" bmkp-bmenu-menubar-menu)) + +;; Top level +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-quit] + '(menu-item "Quit" bmkp-bmenu-quit + :help "Quit the bookmark list, saving its state and the current set of bookmarks")) +(define-key bmkp-bmenu-menubar-menu [bmkp-list-defuns-in-commands-file] + '(menu-item "List User-Defined Bookmark Commands" bmkp-list-defuns-in-commands-file + :help "List the functions defined in `bmkp-bmenu-commands-file'")) +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-describe-marked] + '(menu-item "Describe Marked Bookmarks" bmkp-bmenu-describe-marked + :help "Describe the marked bookmarks. With `C-u' show internal format.")) +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-describe-this-bookmark] + '(menu-item "Describe This Bookmark" bmkp-bmenu-describe-this-bookmark + :help "Describe this line's bookmark. With `C-u' show internal format.")) +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-mode-status-help] + '(menu-item "Current Status, Mode Help" bmkp-bmenu-mode-status-help :keys "?" + :help "Describe `*Bookmark List*' and show its current status")) + +(define-key bmkp-bmenu-menubar-menu [top-sep7] '("--")) ; ------------ +(define-key bmkp-bmenu-menubar-menu [bmkp-revert-bookmark-file] + '(menu-item "Revert to Saved..." bmkp-revert-bookmark-file + :help "Revert to bookmarks in current bookmark file, as last saved" :keys "C-u g")) +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-refresh-menu-list] + '(menu-item "Refresh to Current" bmkp-bmenu-refresh-menu-list + :help "Update display to reflect current bookmark list (`C-u': revert from file)")) + +(define-key bmkp-bmenu-menubar-menu [top-sep6] '("--")) ; ------------ +(define-key bmkp-bmenu-menubar-menu [bmkp-save-menu-list-state] + '(menu-item "Save Display State..." bmkp-save-menu-list-state + :help "Save the current bookmark-list display state to `bmkp-bmenu-state-file'" + :enable (and (not bmkp-bmenu-first-time-p) bmkp-bmenu-state-file))) +(define-key bmkp-bmenu-menubar-menu [bookmark-write] + '(menu-item "Save As..." bookmark-write + :help "Write the current set of bookmarks to a file whose name you enter")) +(define-key bmkp-bmenu-menubar-menu [bookmark-bmenu-save] + '(menu-item "Save" bookmark-bmenu-save + :help "Save the current set of bookmarks to the current bookmark file" + :enable (> bookmark-alist-modification-count 0))) + +(define-key bmkp-bmenu-menubar-menu [top-sep5] '("--")) ; ---------- +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-relocate-marked] + '(menu-item "Relocate Marked..." bmkp-bmenu-relocate-marked + :help "Relocate the marked bookmarks to a directory")) + +(define-key bmkp-bmenu-menubar-menu [top-sep4] '("--")) ; ---------- +(define-key bmkp-bmenu-menubar-menu [bmkp-make-function-bookmark] + '(menu-item "New Function Bookmark..." bmkp-make-function-bookmark + :help "Create a bookmark that will invoke FUNCTION when \"jumped\" to")) +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-make-sequence-from-marked] + '(menu-item "New Sequence Bookmark from Marked..." bmkp-bmenu-make-sequence-from-marked + :help "Create or update a sequence bookmark from the visible marked bookmarks")) +(define-key bmkp-bmenu-menubar-menu [bmkp-bmenu-clone-bookmark] + '(menu-item "Clone (Duplicate) This Bookmark" bmkp-bmenu-clone-bookmark + :help "Clone this bookmark. (`\\[bmkp-bmenu-edit-bookmark-record]' to edit.)")) + +(define-key bmkp-bmenu-menubar-menu [top-sep3] '("--")) ; ---------- +(define-key bmkp-bmenu-menubar-menu [bmkp-choose-navlist-from-bookmark-list] + '(menu-item "Set Navlist from Bookmark-List Bookmark..." bmkp-choose-navlist-from-bookmark-list + :help "Set the navigation list from a bookmark-list bookmark")) +(define-key bmkp-bmenu-menubar-menu [bmkp-choose-navlist-of-type] + '(menu-item "Set Navlist to Bookmarks of Type..." bmkp-choose-navlist-of-type + :help "Set the navigation list to the bookmarks of a certain type")) + +(define-key bmkp-bmenu-menubar-menu [top-sep2] '("--")) ; ---------- + +(defvar bmkp-bmenu-define-command-menu (make-sparse-keymap "Define Command") + "`Define Command' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [define-command] + (cons "Define Command" bmkp-bmenu-define-command-menu)) + +(defvar bmkp-bmenu-bookmark-file-menu (make-sparse-keymap "Bookmark File") + "`Bookmark File' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [bookmark-file] (cons "Bookmark File" bmkp-bmenu-bookmark-file-menu)) + +(when (or (featurep 'bookmark+-lit) + (and (fboundp 'diredp-highlight-autofiles-mode) (featurep 'highlight))) + (defvar bmkp-bmenu-highlight-menu (make-sparse-keymap "Highlight") + "`Highlight' submenu for menu-bar `Bookmark+' menu.") + (define-key bmkp-bmenu-menubar-menu [highlight] (cons "Highlight" bmkp-bmenu-highlight-menu))) + +(defvar bmkp-bmenu-tags-menu (make-sparse-keymap "Tags") + "`Tags' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [tags] (cons "Tags" bmkp-bmenu-tags-menu)) + +(defvar bmkp-bmenu-search-menu (make-sparse-keymap "Search") + "`Search' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [search] (cons "Search" bmkp-bmenu-search-menu)) + +(defvar bmkp-bmenu-sort-menu (make-sparse-keymap "Sort") + "`Sort' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [sort] (cons "Sort" bmkp-bmenu-sort-menu)) + +(defvar bmkp-bmenu-edit-menu (make-sparse-keymap "Edit") + "`Edit' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [edit] (cons "Edit" bmkp-bmenu-edit-menu)) + +(defvar bmkp-bmenu-show-menu (make-sparse-keymap "Show") + "`Show' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [show] (cons "Show" bmkp-bmenu-show-menu)) + +(defvar bmkp-bmenu-omit-menu (make-sparse-keymap "Omit") + "`Omit' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [omitting] (cons "Omit" bmkp-bmenu-omit-menu)) + +(defvar bmkp-bmenu-mark-menu (make-sparse-keymap "Mark") + "`Mark' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [marking] (cons "Mark" bmkp-bmenu-mark-menu)) + +(defvar bmkp-bmenu-delete-menu (make-sparse-keymap "Delete") + "`Delete' submenu for menu-bar `Bookmark+' menu.") +(define-key bmkp-bmenu-menubar-menu [delete] (cons "Delete" bmkp-bmenu-delete-menu)) + +(defvar bmkp-bmenu-toggle-menu (make-sparse-keymap "Toggle") + "`Toggle' submenu for menu-bar menus `Bookmark+' and `Bookmarks'.") +(define-key bmkp-bmenu-menubar-menu [toggle] (cons "Toggle" bmkp-bmenu-toggle-menu)) + + +;;; `Define Command' submenu ----------------------------------------- +(define-key bmkp-bmenu-define-command-menu [bmkp-bmenu-define-full-snapshot-command] + '(menu-item "To Restore Full Bookmark-List State..." bmkp-bmenu-define-full-snapshot-command + :help "Define a command to restore the current bookmark-list state")) +(define-key bmkp-bmenu-define-command-menu [bmkp-bmenu-define-command] + '(menu-item "To Restore Current Order and Filter..." bmkp-bmenu-define-command + :help "Define a command to use the current sort order, filter, and omit list")) +(define-key bmkp-bmenu-define-command-menu [bmkp-define-tags-sort-command] + '(menu-item "To Sort by Specific Tags..." bmkp-define-tags-sort-command + :help "Define a command to sort bookmarks in the bookmark list by certain tags")) +(define-key bmkp-bmenu-define-command-menu [bmkp-bmenu-define-jump-marked-command] + '(menu-item "To Jump to a Bookmark Now Marked..." bmkp-bmenu-define-jump-marked-command + :help "Define a command to jump to one of the bookmarks that is now marked" + :enable bmkp-bmenu-marked-bookmarks)) + + +;;; `Bookmark File' submenu ------------------------------------------ +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-set-bookmark-file-bookmark-from-marked] + '(menu-item "Set Bookmark-File Bookmark from Marked..." + bmkp-bmenu-set-bookmark-file-bookmark-from-marked + :help "Create a bookmark file and a bookmark for it, from the marked bookmarks" + :keys "C-u Y > 0")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-create-bookmark-file-from-marked] + '(menu-item "Copy Marked to New Bookmark File..." bmkp-bmenu-create-bookmark-file-from-marked + :help "Create a bookmark file by copying the marked bookmarks (or current bookmark)")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-copy-marked-to-bookmark-file] + '(menu-item "Copy Marked to Bookmark File..." bmkp-bmenu-copy-marked-to-bookmark-file + :help "Copy the marked bookmarks (or current bookmark) to a bookmark file")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-move-marked-to-bookmark-file] + '(menu-item "Move Marked to Bookmark File..." bmkp-bmenu-move-marked-to-bookmark-file + :help "Move the marked bookmarks (or current bookmark) to a different bookmark file")) + +(define-key bmkp-bmenu-bookmark-file-menu [sep] '("--")) ; ------------ +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-load-marked-bookmark-file-bookmarks] + '(menu-item "Load Marked Bookmark-File Bookmarks..." bmkp-bmenu-load-marked-bookmark-file-bookmarks + :help "Load the marked bookmark-file bookmarks, in order")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-load-marking-unmark-first] + '(menu-item "Load Bookmarks, Mark Only Those Loaded...." bmkp-bmenu-load-marking-unmark-first + :help "`bookmark-load', marking those loaded, unmarking others")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-bmenu-load-marking] + '(menu-item "Load Bookmarks, Mark Those Loaded...." bmkp-bmenu-load-marking + :help "`bookmark-load', marking bookmarks that are loaded")) +(define-key bmkp-bmenu-bookmark-file-menu [bf-sep2] '("--")) ; ------------ +;;; (define-key bmkp-bmenu-bookmark-file-menu [bmkp-save-bookmarks-this-file/buffer] +;;; '(menu-item "Save Bookmarks Here to File (No Switch)..." bmkp-save-bookmarks-this-file/buffer +;;; :help "Save bookmarks defined for the current file or buffer to file")) +;;; (define-key bmkp-bmenu-bookmark-file-menu [bmkp-switch-to-bookmark-file-this-file/buffer] +;;; '(menu-item "Switch to Bookmarks Here..." bmkp-switch-to-bookmark-file-this-file/buffer +;;; :help "Switch to a bookmark file with only bookmarks for this file or buffer")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-switch-to-last-bookmark-file] + '(menu-item "Switch to Last Bookmark File" bmkp-switch-to-last-bookmark-file + :help "Switch back to last set of bookmarks used, *replacing* current set" :keys "C-u L")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-switch-bookmark-file-create] + '(menu-item "Switch to Bookmarks..." bmkp-switch-bookmark-file-create + :help "Switch to another bookmark file, *replacing* the current set of bookmarks")) +(define-key bmkp-bmenu-bookmark-file-menu [bookmark-bmenu-load] + '(menu-item "Load (Add) Bookmarks..." bookmark-bmenu-load + :help "Load additional bookmarks from a bookmark file")) +(define-key bmkp-bmenu-bookmark-file-menu [bf-sep1] '("--")) ; ------------ +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-empty-file] + '(menu-item "Empty Bookmark File..." bmkp-empty-file + :help "Empty an existing bookmark file or create a new, empty bookmark file")) +(define-key bmkp-bmenu-bookmark-file-menu [bmkp-revert-bookmark-file] + '(menu-item "Revert to Saved Bookmarks..." bmkp-revert-bookmark-file + :help "Revert to bookmarks in current bookmark file, as last saved" :keys "C-u g")) + + +;;; `Toggle' submenu ------------------------------------------------- + +(define-key bmkp-bmenu-toggle-menu [diredp-highlight-autofiles-mode] + (bmkp-menu-bar-make-toggle diredp-highlight-autofiles-mode + diredp-highlight-autofiles-mode + "Autofile Highlighting in Dired" + "Whether to highlight autofile bookmarks in Dired us biw %s" + "Toggle the value of option `diredp-highlight-autofiles-mode'" + nil + :visible (and (fboundp 'diredp-highlight-autofiles-mode) + (featurep 'highlight)))) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-guess-default-file-handler] + (bmkp-menu-bar-make-toggle bmkp-toggle-guess-default-file-handler + bmkp-guess-default-handler-for-file-flag + "Guessing Default File Handler" + "Guessing the default handler when creating a file bookmark is now %s" + "Toggle the value of option `bmkp-guess-default-handler-for-file-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-auto-light-when-jump-menu] + (bmkp-menu-bar-make-toggle bmkp-toggle-auto-light-when-jump-menu bmkp-auto-light-when-jump + "Automatic Highlighting When Jumping" + "Bookmark highlighting when you jump to a bookmark is now %s" + "Toggle the value of option `bmkp-auto-light-when-jump'" + (bmkp-toggle-auto-light-when-jump) + :visible (featurep 'bookmark+-lit))) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-auto-light-when-set-menu] + (bmkp-menu-bar-make-toggle bmkp-toggle-auto-light-when-set-menu bmkp-auto-light-when-set + "Automatic Highlighting When Setting" + "Bookmark highlighting when you set a bookmark is now %s" + "Toggle the value of option `bmkp-auto-light-when-set'" + (bmkp-toggle-auto-light-when-set) + :visible (featurep 'bookmark+-lit))) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-prompt-for-tags] + (bmkp-menu-bar-make-toggle bmkp-toggle-prompt-for-tags bmkp-prompt-for-tags-flag + "Prompting for Tags When Setting" + "Prompting for tags when you set a bookmark is now %s" + "Toggle the value of option `bmkp-prompt-for-tags-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-propertize-bookmark-names] + (bmkp-menu-bar-make-toggle bmkp-toggle-propertize-bookmark-names bmkp-propertize-bookmark-names-flag + "Allowing Identical Bookmark Names" + "Allowing multiple bookmarks with the same name is now %s" + "Toggle the value of option `bmkp-propertize-bookmark-names-flag'" + nil + :visible (> emacs-major-version 20))) + +(define-key bmkp-bmenu-toggle-menu [sep4] '("--")) ; ------------ Jumping-behavior stuff +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-w3m-allow-multiple-buffers] + (bmkp-menu-bar-make-toggle bmkp-toggle-w3m-allow-multiple-buffers bmkp-w3m-allow-multiple-buffers-flag + "Using Multiple Buffers for W3M" + "Using a new buffer when jumping to a W3M bookmark is now %s" + "Toggle the value of option `bmkp-w3m-allow-multiple-buffers-flag'")) +(when (boundp 'bmkp-eww-allow-multiple-buffers-flag) ; Emacs 25+ + (define-key bmkp-bmenu-toggle-menu [bmkp-toggle-eww-allow-multiple-buffers] + (bmkp-menu-bar-make-toggle bmkp-toggle-eww-allow-multiple-buffers bmkp-eww-allow-multiple-buffers-flag + "Using Multiple Buffers for EWW" + "Using a new buffer when jumping to an EWW bookmark is now %s" + "Toggle the value of option `bmkp-eww-allow-multiple-buffers-flag'")) + ) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-showing-region-end] + (bmkp-menu-bar-make-toggle bmkp-toggle-showing-region-end bmkp-show-end-of-region-flag + "Showing Region End" + "Showing the end of the region when activating is now %s" + "Toggle the value of option `bmkp-show-end-of-region-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-pop-to] + (bmkp-menu-bar-make-toggle bmkp-toggle-pop-to bmkp-other-window-pop-to-flag + "Using `pop-to-buffer'" + "Using `pop-to-buffer' instead of `switch-to-buffer-other-window' is now %s" + "Toggle the value of option `bmkp-other-window-pop-to-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-auto-light-when-jump-menu] + (bmkp-menu-bar-make-toggle bmkp-toggle-auto-light-when-jump-menu bmkp-auto-light-when-jump + "Automatic Highlighting When Jumping" + "Bookmark highlighting when you jump to a bookmark is now %s" + "Toggle the value of option `bmkp-auto-light-when-jump'" + (progn (bmkp-toggle-auto-light-when-jump) bmkp-auto-light-when-jump) + :visible (featurep 'bookmark+-lit))) +(when (> emacs-major-version 21) + (define-key bmkp-bmenu-toggle-menu [bmkp-toggle-crosshairs] + (bmkp-menu-bar-make-toggle bmkp-toggle-crosshairs bmkp-crosshairs-flag + "Crosshairs Highlighting" + "Highlighting bookmark location with crosshairs is now %s" + "Toggle the value of option `bmkp-crosshairs-flag'" + nil + :visible (featurep 'crosshairs)))) + +(define-key bmkp-bmenu-toggle-menu [sep3] '("--")) ; ------------ Temporary bookmark stuff +(define-key bmkp-bmenu-toggle-menu [bmkp-bmenu-toggle-marked-temporary/savable] + '(menu-item "Temporary/Savable (`X') for Marked" bmkp-bmenu-toggle-marked-temporary/savable + :help "Toggle the temporary (`X') vs. savable status of the marked bookmarks")) +(define-key bmkp-bmenu-toggle-menu [bmkp-temporary-bookmarking-mode] + (bmkp-menu-bar-make-toggle bmkp-temporary-bookmarking-mode bmkp-temporary-bookmarking-mode + "Temporary Bookmarking" + "Temporary bookmarking mode is now %s" + "Toggle automatically saving bookmark changes")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-autotemp-on-set] + (bmkp-menu-bar-make-toggle bmkp-toggle-autotemp-on-set bmkp-autotemp-all-when-set-p + "Making Bookmarks Temporary When Set" + "Automatically making bookmarks temporary when you set them is now %s" + "Toggle automatically making a bookmark temporary when you set it")) + +(define-key bmkp-bmenu-toggle-menu [sep2] '("--")) ; ------------ List display stuff +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-bookmark-set-refreshes] + '(menu-item "Autorefresh for `bmkp-latest-bookmark-alist'" bmkp-toggle-bookmark-set-refreshes + :help "Toggle whether `bookmark-set' refreshes `bmkp-latest-bookmark-alist'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-count-multi-mods-as-one] + (bmkp-menu-bar-make-toggle bmkp-toggle-count-multi-mods-as-one bmkp-count-multi-mods-as-one-flag + "Counting Multiple Modifications As One" + "Counting multiple modifications as one is now %s" + "Toggle the value of option `bmkp-count-multi-mods-as-one-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-bmenu-toggle-marks] + '(menu-item "Marked/Unmarked" bmkp-bmenu-toggle-marks + :help "Unmark all marked bookmarks; mark all unmarked bookmarks")) +(define-key bmkp-bmenu-toggle-menu [bmkp-reverse-sort-order] + '(menu-item "Sort Direction" bmkp-reverse-sort-order + :help "Toggle the current bookmark sort direction" + :enable (bmkp-current-sort-order))) +(define-key bmkp-bmenu-toggle-menu [bmkp-bmenu-toggle-show-only-unmarked] + '(menu-item "Showing Only Unmarked" bmkp-bmenu-toggle-show-only-unmarked + :help "Alternately show unmarked or all bookmarks")) +(define-key bmkp-bmenu-toggle-menu [bmkp-bmenu-toggle-show-only-marked] + '(menu-item "Showing Only Marked" bmkp-bmenu-toggle-show-only-marked + :help "Alternately show unmarked or all bookmarks")) +(define-key bmkp-bmenu-toggle-menu [bmkp-bmenu-toggle-filenames] + (bmkp-menu-bar-make-toggle bmkp-bmenu-toggle-filenames bookmark-bmenu-toggle-filenames + "Showing File Names" + "Showing file names is now %s" + "Toggle the value of option `bookmark-bmenu-toggle-filenames'" + (progn + (custom-load-symbol 'bookmark-bmenu-toggle-filenames) + (let ((set (or (get 'bookmark-bmenu-toggle-filenames 'custom-set) + 'set-default)) + (get (or (get 'bookmark-bmenu-toggle-filenames 'custom-get) + 'default-value))) + (funcall set 'bookmark-bmenu-toggle-filenames + (not (funcall get 'bookmark-bmenu-toggle-filenames)))) + (if bookmark-bmenu-toggle-filenames + (bookmark-bmenu-show-filenames) + (bookmark-bmenu-hide-filenames)) + bookmark-bmenu-toggle-filenames) + :keys "M-t")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-saving-menu-list-state] + (bmkp-menu-bar-make-toggle bmkp-toggle-saving-menu-list-state bmkp-bmenu-state-file + "Saving Display State" + "Ability to save bookmark list state, and autosaving, are now %s" + "Toggle the value of option `bmkp-bmenu-state-file'")) + +(define-key bmkp-bmenu-toggle-menu [sep1] '("--")) ; ------------ Automatic stuff +(define-key bmkp-bmenu-toggle-menu [bmkp-automatic-bookmark-mode] + '(menu-item "Automatically Creating Bookmarks" bmkp-automatic-bookmark-mode + :help "Toggle the periodic automatic creation of bookmarks")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-save-desktop-before-switching] + (bmkp-menu-bar-make-toggle bmkp-toggle-save-desktop-before-switching bmkp-desktop-jump-save-before-flag + "Autosaving the Desktop Before Switching" + "Autosaving the desktop before jumping to a desktop bookmark is now %s" + "Toggle the value of option `bmkp-desktop-jump-save-before-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-saving-relocated] + (bmkp-menu-bar-make-toggle bmkp-toggle-saving-relocated bmkp-save-new-location-flag + "Autosaving Relocated Bookmarks" + "Automatically saving relocated bookmarks is now %s" + "Toggle the value of option `bmkp-save-new-location-flag'")) +(define-key bmkp-bmenu-toggle-menu [bmkp-toggle-saving-bookmark-file] + (bmkp-menu-bar-make-toggle bmkp-toggle-saving-bookmark-file bookmark-save-flag + "Autosaving Bookmark File" + "Automatically saving the bookmark file (`bookmark-save-flag') is now %s" + "Toggle the value of option `bookmark-save-flag'")) + + +;;; `Highlight' submenu ---------------------------------------------- +(when (boundp 'bmkp-bmenu-highlight-menu) + (define-key bmkp-bmenu-highlight-menu [diredp-highlight-autofiles-mode] + (bmkp-menu-bar-make-toggle diredp-highlight-autofiles-mode + diredp-highlight-autofiles-mode + "Toggle Autofile Highlighting in Dired" + "Whether to highlight autofile bookmarks in Dired us biw %s" + "Toggle `diredp-highlight-autofiles-mode'" + nil + :visible (and (fboundp 'diredp-highlight-autofiles-mode) + (featurep 'highlight)))) + (when (featurep 'bookmark+-lit) + (define-key bmkp-bmenu-highlight-menu [bmkp-bmenu-show-only-lighted-bookmarks] + '(menu-item "Show Only Highlighted" bmkp-bmenu-show-only-lighted-bookmarks + :help "Display (only) highlighted bookmarks")) + (define-key bmkp-bmenu-highlight-menu [bmkp-bmenu-set-lighting-for-marked] + '(menu-item "Set Highlighting for Marked" bmkp-bmenu-set-lighting-for-marked + :help "Set specific highlighting for the marked bookmarks" + :enable bmkp-bmenu-marked-bookmarks)) + (define-key bmkp-bmenu-highlight-menu [bmkp-bmenu-unlight-marked] + '(menu-item "Unhighlight Marked" bmkp-bmenu-unlight-marked + :help "Unhighlight the marked bookmarks" + :enable bmkp-bmenu-marked-bookmarks)) + (define-key bmkp-bmenu-highlight-menu [bmkp-bmenu-light-marked] + '(menu-item "Highlight Marked" bmkp-bmenu-light-marked + :help "Highlight the marked bookmarks" + :enable bmkp-bmenu-marked-bookmarks)))) + + +;;; `Tags' submenu --------------------------------------------------- +(define-key bmkp-bmenu-tags-menu [bmkp-list-all-tags] + '(menu-item "List All Tags" bmkp-list-all-tags + :help "List all tags used for any bookmarks (`C-u': show full, internal form)")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-list-tags-of-marked] + '(menu-item "List Tags of Marked" bmkp-bmenu-list-tags-of-marked + :help "List all tags used in the marked bookmarks (`C-u': show full, internal form)")) +(define-key bmkp-bmenu-tags-menu [bmkp-purge-notags-autofiles] + '(menu-item "Purge Autofiles with No Tags..." bmkp-purge-notags-autofiles + :help "Delete all autofile bookmarks that have no tags")) +(define-key bmkp-bmenu-tags-menu [bmkp-untag-a-file] + '(menu-item "Untag a File (Remove Some)..." bmkp-untag-a-file + :help "Remove some tags from autofile bookmark for a file")) +(define-key bmkp-bmenu-tags-menu [bmkp-tag-a-file] + '(menu-item "Tag a File (Add Some)..." bmkp-tag-a-file + :help "Add some tags to the autofile bookmark for a file")) + +(define-key bmkp-bmenu-tags-menu [tags-sep] '("--")) ; --------------- +(define-key bmkp-bmenu-tags-menu [bmkp-rename-tag] + '(menu-item "Rename Tag..." bmkp-rename-tag + :help "Rename a tag in all bookmarks, even those not showing")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-edit-marked] + '(menu-item "Edit Tags of Marked (Lisp)" bmkp-bmenu-edit-marked + :help "Edit internal records of marked bookmarks (which include their tags)" + :keys "T > e")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-set-tag-value-for-marked] + '(menu-item "Set Tag Value for Marked..." bmkp-bmenu-set-tag-value-for-marked + :help "Set the value of a tag, for each of the marked bookmarks")) +(define-key bmkp-bmenu-tags-menu [bmkp-remove-tags-from-all] + '(menu-item "Remove Some Tags from All..." bmkp-remove-tags-from-all + :help "Remove a set of tags from all bookmarks")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-remove-tags-from-marked] + '(menu-item "Remove Some Tags from Marked..." bmkp-bmenu-remove-tags-from-marked + :help "Remove a set of tags from each of the marked bookmarks")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-add-tags-to-marked] + '(menu-item "Add Some Tags to Marked..." bmkp-bmenu-add-tags-to-marked + :help "Add a set of tags to each of the marked bookmarks")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-paste-replace-tags-for-marked] + '(menu-item "Paste Tags to Marked (Replace)..." bmkp-bmenu-paste-replace-tags-for-marked + :help "Replace tags for the marked bookmarks with set of tags copied previously")) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-paste-add-tags-to-marked] + '(menu-item "Paste Tags to Marked (Add)..." bmkp-bmenu-paste-add-tags-to-marked + :help "Add tags copied from another bookmark to the marked bookmarks" + :enable bmkp-copied-tags)) +(define-key bmkp-bmenu-tags-menu [bmkp-bmenu-copy-tags] + '(menu-item "Copy Tags from This Bookmark" bmkp-bmenu-copy-tags + :help "Copy tags from this bookmark, so you can paste them to other bookmarks")) + + +;;; `Search' submenu ------------------------------------------------- +(define-key bmkp-bmenu-search-menu [bmkp-bmenu-query-replace-marked-bookmarks-regexp] + '(menu-item "Query-Replace Marked..." bmkp-bmenu-query-replace-marked-bookmarks-regexp + :help "`query-replace-regexp' over all files whose bookmarks are marked")) +(when (fboundp 'bmkp-bmenu-isearch-marked-bookmarks) + (define-key bmkp-bmenu-search-menu [bmkp-bmenu-isearch-marked-bookmarks-regexp] + '(menu-item "Regexp-Isearch Marked..." bmkp-bmenu-isearch-marked-bookmarks-regexp + :help "Regexp Isearch the marked bookmark locations, in their current order")) + (define-key bmkp-bmenu-search-menu [bmkp-bmenu-isearch-marked-bookmarks] + '(menu-item "Isearch Marked..." bmkp-bmenu-isearch-marked-bookmarks + :help "Isearch the marked bookmark locations, in their current order"))) +(define-key bmkp-bmenu-search-menu [bmkp-bmenu-search-marked-bookmarks-regexp] + '(menu-item "Search Marked..." bmkp-bmenu-search-marked-bookmarks-regexp + :help "Regexp-search the files whose bookmarks are marked, in their current order")) + + +;;; `Sort' submenu --------------------------------------------------- +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-url] + '(menu-item "By URL" bmkp-bmenu-sort-by-url + :help "Sort URL bookmarks alphabetically by their URL/filename")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-Gnus-thread] + '(menu-item "By Gnus Thread" bmkp-bmenu-sort-by-Gnus-thread + :help "Sort Gnus bookmarks by group, then by article, then by message")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-Info-node-name] + '(menu-item "By Info Node Name" bmkp-bmenu-sort-by-Info-node-name + :help "Sort Info bookmarks by manual (file) name, then node name, then position")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-Info-position] + '(menu-item "By Info Book Order" bmkp-bmenu-sort-by-Info-position + :help "Sort Info bookmarks by manual (file) name, then position (order in book)")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-last-local-file-update] + '(menu-item "By Last Local File Update" bmkp-bmenu-sort-by-last-local-file-update + :help "Sort bookmarks by last local file update time")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-last-buffer-or-file-access] + '(menu-item "By Last Buffer/File Access" bmkp-bmenu-sort-by-last-buffer-or-file-access + :help "Sort bookmarks by time of last buffer access or local-file access")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-local-file-size] + '(menu-item "By Local File Size" bmkp-bmenu-sort-by-local-file-size + :help "Sort bookmarks by local file size")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-local-file-type] + '(menu-item "By Local File Type" bmkp-bmenu-sort-by-local-file-type + :help "Sort bookmarks by local file type: file, symlink, directory")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-bookmark-type] + '(menu-item "By Type" bmkp-bmenu-sort-by-bookmark-type + :help "Sort bookmarks by type: Info, URL, Gnus, files, other")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-file-name] + '(menu-item "By File Name" bmkp-bmenu-sort-by-file-name :help "Sort bookmarks by file name")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-bookmark-name] + '(menu-item "By Bookmark Name" bmkp-bmenu-sort-by-bookmark-name + :help "Sort bookmarks by bookmark name, respecting `case-fold-search'")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-creation-time] + '(menu-item "By Creation Time" bmkp-bmenu-sort-by-creation-time + :help "Sort bookmarks by the time of their creation")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-last-bookmark-access] + '(menu-item "By Last Bookmark Access" bmkp-bmenu-sort-by-last-bookmark-access + :help "Sort bookmarks by the time of their last visit as bookmarks")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-by-bookmark-visit-frequency] + '(menu-item "By Bookmark Use" bmkp-bmenu-sort-by-bookmark-visit-frequency + :help "Sort bookmarks by the number of times they were visited as bookmarks")) +(define-key bmkp-bmenu-sort-menu [bmkp-bmenu-sort-marked-before-unmarked] + '(menu-item "Marked Before Unmarked" bmkp-bmenu-sort-marked-before-unmarked + :help "Sort bookmarks by putting marked before unmarked")) +(define-key bmkp-bmenu-sort-menu [bmkp-reverse-sort-order] + '(menu-item "Reverse" bmkp-reverse-sort-order :help "Reverse the current bookmark sort order")) + +;;; `Edit' submenu --------------------------------------------------- +(define-key bmkp-bmenu-edit-menu [bmkp-bmenu-edit-marked] + '(menu-item "Edit Full Records of Marked (Lisp)" bmkp-bmenu-edit-marked + :help "Edit the full internal records of the marked bookmarks" :keys "E")) +(define-key bmkp-bmenu-edit-menu [bmkp-bmenu-edit-bookmark-record] + '(menu-item "Edit Full Record (Lisp)" bmkp-bmenu-edit-bookmark-record + :help "Edit full record (Lisp sexp) for this bookmark, in another window")) +(define-key bmkp-bmenu-edit-menu [bmkp-bmenu-edit-annotations-for-marked] + '(menu-item "Edit Annotations of Marked" bmkp-bmenu-edit-annotations-for-marked + :help "Edit annotations (created if missing) for the marked bookmarks")) +(define-key bmkp-bmenu-edit-menu [bookmark-bmenu-edit-annotation] + '(menu-item "Edit Annotation" bookmark-bmenu-edit-annotation + :help "Edit annotation for this bookmark (create if none), in another window")) + +;;; `Show' submenu --------------------------------------------------- +(define-key bmkp-bmenu-show-menu [bookmark-bmenu-show-all-annotations] + '(menu-item "Show All Annotations" bookmark-bmenu-show-all-annotations + :help "Show the annotations for all bookmarks (in another window)")) +(define-key bmkp-bmenu-show-menu [bookmark-bmenu-show-annotation] + '(menu-item "Show Annotation" bookmark-bmenu-show-annotation + :help "Show the annotation for this bookmark (in another window)" + :enable (and (bookmark-bmenu-bookmark) (bookmark-get-annotation (bookmark-bmenu-bookmark))))) +(define-key bmkp-bmenu-show-menu [bookmark-bmenu-toggle-filenames] + '(menu-item "Show/Hide File Names" bookmark-bmenu-toggle-filenames + :help "Toggle whether filenames are shown in the bookmark list")) + +(define-key bmkp-bmenu-show-menu [show-sep5] '("--")) ; -------------- +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-filter-tags-incrementally] + '(menu-item "Show Only Tag Matches..." bmkp-bmenu-filter-tags-incrementally + :help "Incrementally filter bookmarks by tags using a regexp")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-filter-annotation-incrementally] + '(menu-item "Show Only Annotation Matches..." bmkp-bmenu-filter-annotation-incrementally + :help "Incrementally filter bookmarks by annotation using a regexp")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-filter-file-name-incrementally] + '(menu-item "Show Only File Name Matches..." bmkp-bmenu-filter-file-name-incrementally + :help "Incrementally filter bookmarks by file name using a regexp")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-filter-bookmark-name-incrementally] + '(menu-item "Show Only Name Matches..." bmkp-bmenu-filter-bookmark-name-incrementally + :help "Incrementally filter bookmarks by bookmark name using a regexp")) + +(define-key bmkp-bmenu-show-menu [show-sep3] '("--")) ; -------------- +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-only-specific-file-bookmarks] + '(menu-item "Show Only for Specific File" bmkp-bmenu-show-only-specific-file-bookmarks + :help "Display (only) the bookmarks for a specific file")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-only-specific-buffer-bookmarks] + '(menu-item "Show Only for Specific Buffer" bmkp-bmenu-show-only-specific-buffer-bookmarks + :help "Display (only) the bookmarks for a specific buffer")) + +(define-key bmkp-bmenu-show-menu [show-sep2] '("--")) ; -------------- +(when (featurep 'bookmark+-lit) + (define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-only-lighted-bookmarks] + '(menu-item "Show Only Highlighted" bmkp-bmenu-show-only-lighted-bookmarks + :help "Display (only) highlighted bookmarks"))) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-only-temporary-bookmarks] + '(menu-item "Show Only Temporaries" bmkp-bmenu-show-only-temporary-bookmarks + :help "Display (only) the temporary bookmarks (`X')")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-only-autonamed-bookmarks] + '(menu-item "Show Only Autonamed" bmkp-bmenu-show-only-autonamed-bookmarks + :help "Display (only) the autonamed bookmarks")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-only-autofile-bookmarks] + '(menu-item "Show Only Autofiles" bmkp-bmenu-show-only-autofile-bookmarks + :help "Display (only) the autofile bookmarks: those named the same as their files")) + +(define-key bmkp-bmenu-show-menu [show-sep1] '("--")) ; -------------- +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-toggle-show-only-unmarked] + '(menu-item "Show Only Unmarked" bmkp-bmenu-toggle-show-only-unmarked + :help "Hide all marked bookmarks. Repeat to toggle, showing all")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-toggle-show-only-marked] + '(menu-item "Show Only Marked" bmkp-bmenu-toggle-show-only-marked + :help "Hide all unmarked bookmarks. Repeat to toggle, showing all")) +(define-key bmkp-bmenu-show-menu [bmkp-bmenu-show-all] + '(menu-item "Show All" bmkp-bmenu-show-all + :help "Show all bookmarks currently known to the bookmark list")) + + +;;; `Show' > `Only Bookmarks of Type' submenu ----------------------------- + +(defvar bmkp-bmenu-show-types-menu (make-sparse-keymap "Only Bookmarks of Type") + "`Only Bookmarks of Type' submenu for `Show' submenu of `Bookmark+' menu.") +(define-key bmkp-bmenu-show-menu [type] (cons "Only Bookmarks of Type" bmkp-bmenu-show-types-menu)) + +(define-key bmkp-bmenu-show-types-menu [show-sep4] '("--")) ; -------------- +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-w3m-bookmarks] + '(menu-item "W3M URLs" bmkp-bmenu-show-only-w3m-bookmarks + :help "Display (only) the W3M URL bookmarks")) +(when (fboundp 'bmkp-bmenu-show-only-eww-bookmarks) ; Emacs 25+ + (define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-eww-bookmarks] + '(menu-item "EWW URLs" bmkp-bmenu-show-only-eww-bookmarks + :help "Display (only) the EWW URL bookmarks"))) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-url-bookmarks] + '(menu-item "URLs" bmkp-bmenu-show-only-url-bookmarks + :help "Display (only) the URL bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-man-bookmarks] + '(menu-item "UNIX Manual Pages" bmkp-bmenu-show-only-man-bookmarks + :help "Display (only) the `man' page bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-untagged-bookmarks] + '(menu-item "Untagged" bmkp-bmenu-show-only-untagged-bookmarks + :help "Display (only) the bookmarks that do not have tags")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-tagged-bookmarks] + '(menu-item "Tagged" bmkp-bmenu-show-only-tagged-bookmarks + :help "Display (only) the bookmarks that have tags")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-variable-list-bookmarks] + '(menu-item "Variable Lists" bmkp-bmenu-show-only-variable-list-bookmarks + :help "Display (only) the variable-list bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-function-bookmarks] + '(menu-item "Functions" bmkp-bmenu-show-only-function-bookmarks + :help "Display (only) the function bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-snippet-bookmarks] + '(menu-item "Snippets" bmkp-bmenu-show-only-snippet-bookmarks + :help "Display (only) the snippet bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-region-bookmarks] + '(menu-item "Regions" bmkp-bmenu-show-only-region-bookmarks + :help "Display (only) the bookmarks that record a region")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-orphaned-local-file-bookmarks] + '(menu-item "Orphaned Local Files" bmkp-bmenu-show-only-orphaned-local-file-bookmarks + :help "Display (only) orphaned local-file bookmarks (`C-u': show remote also)")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-non-invokable-bookmarks] + '(menu-item "Non-Invokable" bmkp-bmenu-show-only-non-invokable-bookmarks + :help "Display (only) the non-invokable bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-non-file-bookmarks] + '(menu-item "Non-Files (Buffers)" bmkp-bmenu-show-only-non-file-bookmarks + :help "Display (only) the non-file bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-image-bookmarks] + '(menu-item "Image Files" bmkp-bmenu-show-only-image-bookmarks + :help "Display (only) image-file bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-icicles-search-hits-bookmarks] + '(menu-item "Icicles Search-Hits" bmkp-bmenu-show-only-icicles-search-hits-bookmarks + :help "Display (only) Icicles search-hits bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-info-bookmarks] + '(menu-item "Info Nodes" bmkp-bmenu-show-only-info-bookmarks + :help "Display (only) the Info bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-gnus-bookmarks] + '(menu-item "Gnus Messages" bmkp-bmenu-show-only-gnus-bookmarks + :help "Display (only) the Gnus bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-file-bookmarks] + '(menu-item "Files" bmkp-bmenu-show-only-file-bookmarks + :help "Display (only) the file and directory bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-dired-bookmarks] + '(menu-item "Dired Buffers" bmkp-bmenu-show-only-dired-bookmarks + :help "Display (only) the Dired bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-desktop-bookmarks] + '(menu-item "Desktops" bmkp-bmenu-show-only-desktop-bookmarks + :help "Display (only) the desktop bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-bookmark-list-bookmarks] + '(menu-item "Bookmark Lists" bmkp-bmenu-show-only-bookmark-list-bookmarks + :help "Display (only) the bookmark-list bookmarks")) +(define-key bmkp-bmenu-show-types-menu [bmkp-bmenu-show-only-bookmark-file-bookmarks] + '(menu-item "Bookmark Files" bmkp-bmenu-show-only-bookmark-file-bookmarks + :help "Display (only) the bookmark-file bookmarks")) + + +;;; `Omit' submenu --------------------------------------------------- +(define-key bmkp-bmenu-omit-menu [bmkp-bmenu-show-all] + '(menu-item "Show All" bmkp-bmenu-show-all + :visible (eq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only) + :help "Show all bookmarks (except omitted)")) +(define-key bmkp-bmenu-omit-menu [bmkp-bmenu-show-only-omitted-bookmarks] + '(menu-item "Show Only Omitted" bmkp-bmenu-show-only-omitted-bookmarks + :visible (not (eq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only)) + :enable bmkp-bmenu-omitted-bookmarks :help "Show only the omitted bookmarks")) +(define-key bmkp-bmenu-omit-menu [bmkp-unomit-all] + '(menu-item "Un-Omit All" bmkp-unomit-all + :visible bmkp-bmenu-omitted-bookmarks :help "Un-omit all omitted bookmarks")) +(define-key bmkp-bmenu-omit-menu [bmkp-bmenu-unomit-marked] + '(menu-item "Un-Omit Marked" bmkp-bmenu-unomit-marked + :visible (eq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only) + :enable (and bmkp-bmenu-omitted-bookmarks + (save-excursion (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (re-search-forward "^>" (point-max) t))) + :help "Un-omit the marked bookmarks" :keys "\\[bmkp-bmenu-omit/unomit-marked]")) +(define-key bmkp-bmenu-omit-menu [bmkp-bmenu-omit-marked] + '(menu-item "Omit Marked" bmkp-bmenu-omit-marked + :visible (not (eq bmkp-bmenu-filter-function 'bmkp-omitted-alist-only)) + :enable (save-excursion (goto-char (point-min)) (forward-line bmkp-bmenu-header-lines) + (re-search-forward "^>" (point-max) t)) + :help "Omit the marked bookmarks" :keys "\\[bmkp-bmenu-omit/unomit-marked]")) + + +;;; `Mark' submenu --------------------------------------------------- +(define-key bmkp-bmenu-mark-menu [mark-sep5] '("--")) ; -------------- +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-load-marking-unmark-first] + '(menu-item "Load Bookmark File, Mark Only Loaded...." bmkp-bmenu-load-marking-unmark-first + :help "`bookmark-load', marking only bookmarks that are loaded.")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-load-marking] + '(menu-item "Load Bookmark File, Mark Loaded...." bmkp-bmenu-load-marking + :help "`bookmark-load', but mark bookmarks that are loaded. C-u: unmark all first.")) + +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-unmark-bookmarks-tagged-not-all] + '(menu-item "Unmark If Not Tagged with All..." bmkp-bmenu-unmark-bookmarks-tagged-not-all + :help "Unmark all visible bookmarks that are tagged with *some* tag in a set you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-unmark-bookmarks-tagged-none] + '(menu-item "Unmark If Tagged with None..." bmkp-bmenu-unmark-bookmarks-tagged-none + :help "Unmark all visible bookmarks that are *not* tagged with *any* tag you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-unmark-bookmarks-tagged-all] + '(menu-item "Unmark If Tagged with All..." bmkp-bmenu-unmark-bookmarks-tagged-all + :help "Unmark all visible bookmarks that are tagged with *each* tag you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-unmark-bookmarks-tagged-some] + '(menu-item "Unmark If Tagged with Some..." bmkp-bmenu-unmark-bookmarks-tagged-some + :help "Unmark all visible bookmarks that are tagged with *some* tag in a set you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-unmark-bookmarks-tagged-regexp] + '(menu-item "Unmark If Tagged Matching Regexp..." bmkp-bmenu-unmark-bookmarks-tagged-regexp + :help "Unmark bookmarks any of whose tags match a regexp you enter")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-bookmarks-tagged-not-all] + '(menu-item "Mark If Not Tagged with All..." bmkp-bmenu-mark-bookmarks-tagged-not-all + :help "Mark all visible bookmarks that are *not* tagged with *all* tags you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-bookmarks-tagged-none] + '(menu-item "Mark If Tagged with None..." bmkp-bmenu-mark-bookmarks-tagged-none + :help "Mark all visible bookmarks that are not tagged with *any* tag you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-bookmarks-tagged-all] + '(menu-item "Mark If Tagged with All..." bmkp-bmenu-mark-bookmarks-tagged-all + :help "Mark all visible bookmarks that are tagged with *each* tag you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-bookmarks-tagged-some] + '(menu-item "Mark If Tagged with Some..." bmkp-bmenu-mark-bookmarks-tagged-some + :help "Mark all visible bookmarks that are tagged with *some* tag in a set you specify")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-bookmarks-tagged-regexp] + '(menu-item "Mark If Tagged Matching Regexp..." bmkp-bmenu-mark-bookmarks-tagged-regexp + :help "Mark bookmarks any of whose tags match a regexp you enter")) + +(define-key bmkp-bmenu-mark-menu [mark-sep3] '("--")) ; -------------- +(when (featurep 'bookmark+-lit) + (define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-lighted-bookmarks] + '(menu-item "Mark Highlighted" bmkp-bmenu-mark-lighted-bookmarks + :help "Mark highlighted bookmarks"))) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-temporary-bookmarks] + '(menu-item "Mark Temporaries" bmkp-bmenu-mark-temporary-bookmarks + :help "Mark temporary bookmarks (those with `X')")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-autonamed-bookmarks] + '(menu-item "Mark Autonamed" bmkp-bmenu-mark-autonamed-bookmarks + :help "Mark autonamed bookmarks")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-autofile-bookmarks] + '(menu-item "Mark Autofiles" bmkp-bmenu-mark-autofile-bookmarks + :help "Mark autofile bookmarks: those whose names are the same as their files")) + +(define-key bmkp-bmenu-mark-menu [mark-sep2] '("--")) ; -------------- +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-unmark-all] + '(menu-item "Unmark All" bmkp-bmenu-unmark-all + :help "Remove a mark you specify (> or D) from each bookmark (RET to remove both kinds)")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-all] + '(menu-item "Mark All" bmkp-bmenu-mark-all :help "Mark all bookmarks, using mark `>'")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-toggle-marks] + '(menu-item "Toggle Marked/Unmarked" bmkp-bmenu-toggle-marks + :help "Unmark all marked bookmarks; mark all unmarked bookmarks")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-regexp-mark] + '(menu-item "Mark Regexp Matches..." bmkp-bmenu-regexp-mark + :help "Mark bookmarks that match a regexp that you enter")) + +(define-key bmkp-bmenu-mark-menu [mark-sep4] '("--")) ; -------------- +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-specific-file-bookmarks] + '(menu-item "Mark for Specific File" bmkp-bmenu-mark-specific-file-bookmarks + :help "Mark bookmarks for a specific file")) +(define-key bmkp-bmenu-mark-menu [bmkp-bmenu-mark-specific-buffer-bookmarks] + '(menu-item "Mark for Specific Buffer" bmkp-bmenu-mark-specific-buffer-bookmarks + :help "Mark bookmarks for a specific buffer")) + + +;; `Mark' > `Bookmarks of Type' submenu ------------------------------ +(defvar bmkp-bmenu-mark-types-menu (make-sparse-keymap "Bookmarks of Type") + "`Bookmarks of Type' submenu for `Mark' submenu of m`Bookmark+' menu.") +(define-key bmkp-bmenu-mark-menu [type] (cons "Bookmarks of Type" bmkp-bmenu-mark-types-menu)) + +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-w3m-bookmarks] + '(menu-item "W3M URLs" bmkp-bmenu-mark-w3m-bookmarks :help "Mark W3M URL bookmarks")) +(when (fboundp 'bmkp-bmenu-mark-eww-bookmarks) ; Emacs 25+ + (define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-eww-bookmarks] + '(menu-item "EWW URLs" bmkp-bmenu-mark-eww-bookmarks :help "Mark Eww URL bookmarks"))) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-url-bookmarks] + '(menu-item "URLs" bmkp-bmenu-mark-url-bookmarks :help "Mark URL bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-variable-list-bookmarks] + '(menu-item "Variable Lists" bmkp-bmenu-mark-variable-list-bookmarks + :help "Mark the variable-list bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-man-bookmarks] + '(menu-item "UNIX Manual Pages" bmkp-bmenu-mark-man-bookmarks + :help "Mark `man' page bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-snippet-bookmarks] + '(menu-item "Snippets" bmkp-bmenu-mark-snippet-bookmarks + :help "Mark snippet bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-region-bookmarks] + '(menu-item "Regions" bmkp-bmenu-mark-region-bookmarks + :help "Mark bookmarks that record a region")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-orphaned-local-file-bookmarks] + '(menu-item "Orphaned Local Files" bmkp-bmenu-mark-orphaned-local-file-bookmarks + :help "Mark orphaned local-file bookmarks (`C-u': remote also)")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-non-invokable-bookmarks] + '(menu-item "Non-Invokable" bmkp-bmenu-mark-non-invokable-bookmarks + :help "Mark non-invokable bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-non-file-bookmarks] + '(menu-item "Non-Files (Buffers)" bmkp-bmenu-mark-non-file-bookmarks + :help "Mark non-file bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-image-bookmarks] + '(menu-item "Images" bmkp-bmenu-mark-image-bookmarks :help "Mark image-file bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-icicles-search-hits-bookmarks] + '(menu-item "Icicle Search Hits" bmkp-bmenu-mark-icicles-search-hits-bookmarks + :help "Mark Icicles search-hit bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-info-bookmarks] + '(menu-item "Info Nodes" bmkp-bmenu-mark-info-bookmarks :help "Mark Info bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-gnus-bookmarks] + '(menu-item "Gnus Messages" bmkp-bmenu-mark-gnus-bookmarks :help "Mark Gnus bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-file-bookmarks] + '(menu-item "Files" bmkp-bmenu-mark-file-bookmarks :help "Mark file bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-dired-bookmarks] + '(menu-item "Dired Buffers" bmkp-bmenu-mark-dired-bookmarks :help "Mark Dired bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-desktop-bookmarks] + '(menu-item "Desktops" bmkp-bmenu-mark-desktop-bookmarks + :help "Mark desktop bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-bookmark-list-bookmarks] + '(menu-item "Bookmark Lists" bmkp-bmenu-mark-bookmark-list-bookmarks + :help "Mark the bookmark-list bookmarks")) +(define-key bmkp-bmenu-mark-types-menu [bmkp-bmenu-mark-bookmark-file-bookmarks] + '(menu-item "Bookmark Files" bmkp-bmenu-mark-bookmark-file-bookmarks + :help "Mark the bookmark-file bookmarks")) + + +;;; `Delete' submenu ------------------------------------------------- +(define-key bmkp-bmenu-delete-menu [bookmark-bmenu-execute-deletions] + '(menu-item "Delete Flagged (D)..." bookmark-bmenu-execute-deletions + :help "Delete the (visible) bookmarks flagged `D'")) +(define-key bmkp-bmenu-delete-menu [bmkp-bmenu-delete-marked] + '(menu-item "Delete Marked (>)..." bmkp-bmenu-delete-marked + :help "Delete all (visible) bookmarks marked `>', after confirmation")) +(define-key bmkp-bmenu-delete-menu [bmkp-delete-all-temporary-bookmarks] + '(menu-item "Delete All Temporaries..." bmkp-delete-all-temporary-bookmarks + :help "Delete the temporary bookmarks, (`X') whether visible here or not")) + + +;;; `Edit' menu-bar menu + +;; `menu-bar+.el' redefines `menu-bar-edit-menu'. +;; Soft-require it in `condition-case' because it soft-requires Bookmark+. +(condition-case nil (require 'menu-bar+ nil t) (error nil)) + +(define-key-after menu-bar-edit-menu [separator-snippet] '("--") 'mark-whole-buffer) +(define-key-after menu-bar-edit-menu [bmkp-set-snippet-bookmark] + '(menu-item "Region to Snippet..." bmkp-set-snippet-bookmark + :help "Save the region text to a snippet bookmark" + :enable (and mark-active (not buffer-read-only))) 'separator-snippet) +(define-key-after menu-bar-edit-menu [bmkp-snippet-to-kill-ring] + '(menu-item "Snippet to Kill Ring..." bmkp-snippet-to-kill-ring + :help "Copy the text saved in a snippet bookmark to the `kill-ring'") + 'bmkp-set-snippet-bookmark) + + + +;;;--------------------------------------------------------------------------------------- + +;;; Mouse-3 menu binding. + +(defvar bmkp-bmenu-line-overlay nil + "Overlay to highlight the current line for `bmkp-bmenu-mouse-3-menu'.") +(define-key bookmark-bmenu-mode-map [down-mouse-3] 'bmkp-bmenu-mouse-3-menu) +(define-key bookmark-bmenu-mode-map [mouse-3] 'ignore) + +;;;###autoload (autoload 'bmkp-bmenu-mouse-3-menu "bookmark+") +(defun bmkp-bmenu-mouse-3-menu (event) + "Pop-up menu on `mouse-3' for a bookmark listed in `*Bookmark List*'." + (interactive "e") + (let* ((mouse-pos (event-start event)) + (inhibit-field-text-motion t) ; Just in case. + bol eol bmk-name) + (with-current-buffer (window-buffer (posn-window mouse-pos)) + (save-excursion + (goto-char (posn-point mouse-pos)) + (setq bol (line-beginning-position) + eol (line-end-position)) + (unwind-protect + (progn + (if bmkp-bmenu-line-overlay ; Don't re-create. + (move-overlay bmkp-bmenu-line-overlay bol eol (current-buffer)) + (setq bmkp-bmenu-line-overlay (make-overlay bol eol)) + (overlay-put bmkp-bmenu-line-overlay 'face 'region)) + (setq bmk-name (bookmark-bmenu-bookmark)) + (when bmk-name + (sit-for 0) + (let* ((map (easy-menu-create-menu + "This Bookmark" + `(,(if (bmkp-bookmark-name-member bmk-name bmkp-bmenu-marked-bookmarks) + ["Unmark" bookmark-bmenu-unmark] + ["Mark" bookmark-bmenu-mark]) + ,(save-excursion + (goto-char (posn-point mouse-pos)) + (beginning-of-line) + (if (bmkp-looking-at-p "^D") + ["Unmark" bookmark-bmenu-unmark] + ["Flag for Deletion" bmkp-bmenu-flag-for-deletion])) + ["Omit" bmkp-bmenu-omit] + ["Jump To" bookmark-bmenu-this-window] + ["Jump To in Other Window" bookmark-bmenu-other-window] + + "--" ; ---------------------------------------------------- + ["Edit Tags..." bmkp-bmenu-edit-tags + :active (bmkp-get-tags bmk-name)] + ["Copy Tags" bmkp-bmenu-copy-tags + ;; You can copy an empty list of tags and paste-replace with it. + ;; :active (bmkp-get-tags bmk-name) + ] + ["Paste Tags (Add)" bmkp-bmenu-paste-add-tags + :active bmkp-copied-tags] + ["Paste Tags (Replace)" bmkp-bmenu-paste-replace-tags + ;; You can paste an empty list of tags to replace tags. + ;; :active bmkp-copied-tags + ] + ["Add Some Tags..." bmkp-bmenu-add-tags] + ["Remove Some Tags..." bmkp-bmenu-remove-tags + :active (bmkp-get-tags bmk-name)] + ["Remove All Tags..." bmkp-bmenu-remove-all-tags + :active (bmkp-get-tags bmk-name)] + ["Set Tag Value..." bmkp-bmenu-set-tag-value + :active (bmkp-get-tags bmk-name)] + ["Rename Tag..." bmkp-rename-tag + :active (bmkp-get-tags bmk-name)] + + ["--" 'ignore :visible (featurep 'bookmark+-lit)] ; --------------- + ["Highlight" bmkp-bmenu-light + :visible (featurep 'bookmark+-lit) + :active (not (bmkp-lighted-p bmk-name))] + ["Unhighlight" bmkp-bmenu-unlight + :visible (featurep 'bookmark+-lit) + :active (bmkp-lighted-p bmk-name)] + ["Set Lighting" bmkp-bmenu-set-lighting + :visible (featurep 'bookmark+-lit)] + + "--" ; ---------------------------------------------------- + ["Toggle Temporary/Savable" bmkp-bmenu-toggle-temporary] + ,@(and (fboundp 'org-add-link-type) + '(["Store Org Link" org-store-link])) + ["Rename or Relocate..." bmkp-bmenu-edit-bookmark-name-and-location] + ["Clone (Duplicate)" bmkp-bmenu-clone-bookmark] + ["Edit Internal Record (Lisp)..." bmkp-bmenu-edit-bookmark-record] + ["Show Annotation" bookmark-bmenu-show-annotation + :active (bookmark-get-annotation bmk-name)] + ["Edit Annotation..." bookmark-bmenu-edit-annotation] + + "--" ; ---------------------------------------------------- + ["Describe" bmkp-bmenu-describe-this-bookmark]))) + (choice (x-popup-menu event map))) + (when choice + (call-interactively (lookup-key map (apply 'vector choice))))))) + (when bmkp-bmenu-line-overlay (delete-overlay bmkp-bmenu-line-overlay))))))) + +;;;;;;;;;;;;;;;;;;;;; + +(provide 'bookmark+-bmu) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-bmu.el ends here diff --git a/lisp/bookmark+-chg.el b/lisp/bookmark+-chg.el new file mode 100644 index 00000000..3c8653b6 --- /dev/null +++ b/lisp/bookmark+-chg.el @@ -0,0 +1,3703 @@ +;;; bookmark+-chg.el - Change logs for Bookmark+ libraries. +;; +;; Filename: bookmark+-chg.el +;; Description: Change logs for Bookmark+ libraries. +;; Author: Drew Adams +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2000-2022, Drew Adams, all rights reserved. +;; Created: Fri Sep 15 07:58:41 2000 +;; Last-Updated: Fri Jan 14 12:54:17 2022 (-0800) +;; By: dradams +;; Update #: 16855 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-chg.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+ +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26. +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Change log for the Bookmark+ libraries, which extend standard +;; library `bookmark.el'. This file contains no code, so you need +;; not load it. +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) code library +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit' - (optional) code for highlighting bookmarks +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (bmenu) +;; `bookmark+-1.el' - other (non-bmenu) required code +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc' - documentation (comment-only file) +;; `bookmark+-chg' - change log (this file) +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you put library +;; `bookmark+-doc.el' in your `load-path'.) +;; +;; +;; ****** NOTE ****** +;; +;; WHENEVER you update Bookmark+ (i.e., download new versions of +;; Bookmark+ source files), I recommend that you do the +;; following: +;; +;; 1. Delete ALL existing BYTE-COMPILED Bookmark+ files +;; (bookmark+*.elc). +;; 2. Load Bookmark+ (`load-library' or `require'). +;; 3. Byte-compile the source files. +;; +;; In particular, ALWAYS LOAD `bookmark+-mac.el' (not +;; `bookmark+-mac.elc') BEFORE YOU BYTE-COMPILE new versions of +;; the files, in case there have been any changes to Lisp macros +;; (in `bookmark+-mac.el'). +;; +;; (This is standard procedure for Lisp: code that depends on +;; macros needs to be byte-compiled anew after loading the +;; updated macros.) +;; +;; ****************** +;; +;; +;; ****** NOTE ****** +;; +;; On 2010-06-18, I changed the prefix used by package Bookmark+ +;; from `bookmarkp-' to `bmkp-'. THIS IS AN INCOMPATIBLE CHANGE. +;; I apologize for the inconvenience, but the new prefix is +;; preferable for a number of reasons, including easier +;; distinction from standard `bookmark.el' names. +;; +;; This change means that YOU MUST MANUALLY REPLACE ALL +;; OCCURRENCES of `bookmarkp-' by `bmkp-' in the following +;; places, if you used Bookmark+ prior to this change: +;; +;; 1. In your init file (`~/.emacs') or your `custom-file', if +;; you have one. This is needed if you customized any +;; Bookmark+ features. +;; +;; 2. In your default bookmark file, `bookmark-default-file' +;; (`.emacs.bmk'), and in any other bookmark files you might +;; have. +;; +;; 3. In your `*Bookmark List*' state file, +;; `bmkp-bmenu-state-file' (`~/.emacs-bmk-bmenu-state.el'). +;; +;; 4. In your `*Bookmark List*' commands file, +;; `bmkp-bmenu-commands-file' (`~/.emacs-bmk-bmenu-commands.el'), +;; if you have one. +;; +;; You can do this editing in a virgin Emacs session (`emacs +;; -Q'), that is, without loading Bookmark+. +;; +;; Alternatively, you can do this editing in an Emacs session +;; where Bookmark+ has been loaded, but in that case you must +;; TURN OFF AUTOMATIC SAVING of both your default bookmark file +;; and your `*Bookmark List*' state file. Otherwise, when you +;; quit Emacs your manually edits will be overwritten. +;; +;; To turn off this automatic saving, you can use `M-~' and `M-l' +;; in buffer `*Bookmark List*' (commands +;; `bmkp-toggle-saving-bookmark-file' and +;; `bmkp-toggle-saving-menu-list-state' - they are also in the +;; `Bookmark+' menu). +;; +;; +;; Again, sorry for this inconvenience. +;; +;; ****************** + +;;(@> "Index") +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "CHANGE LOG FOR `bookmark+-1.el'") +;; (@> "CHANGE LOG FOR `bookmark+-bmu.el'") +;; (@> "CHANGE LOG FOR `bookmark+-doc.el'") +;; (@> "CHANGE LOG FOR `bookmark+-key.el'") +;; (@> "CHANGE LOG FOR `bookmark+-lit.el'") +;; (@> "CHANGE LOG FOR `bookmark+-mac.el'") +;; (@> "CHANGE LOG FOR `bookmark+.el'") + +;;;(@* "CHANGE LOG FOR `bookmark+-1.el'") +;; +;; 2021/09/19 dadams +;; Everywhere: Use bmkp-bmenu-buffer, not vanilla bookmark-bmenu-buffer. +;; bmkp-bmenu-barf-if-not-in-menu-list: Test mode with derived-mode-p; don't test buffer name. +;; 2020/08/21 dadams +;; bookmark-set: Moved making bmk temporary before bookmark-store, and pass RECORD, not BNAME. +;; bmkp(*)-automatic*: Put defvaralias symbols in right order. +;; 2021/08/18 dadams +;; Added: bmkp-set-automatic-bookmark. +;; Renamed: bmkp(*)-auto-idle* to bmkp(*)-automatic*. Added defvaralias for old names. +;; 2021/04/18 dadams +;; Added back a redefinition of bookmark-get-bookmark, as bmkp-get-bookmark with NO-NAME-CHECK-P. +;; bookmark-set-name, bookmark-location: +;; Replaced (bmkp-get-bookmark BMK nil 'NO-NAME-CHECK-P) with (bookmark-get-bookmark BMK). +;; Doc string and comment improvements, vis a vis uses of bookmark|bmkp-get-bookmark. +;; 2021/04/16 dadams +;; bookmark-get-bookmark-record, bookmark-set-name, bookmark-prop-set, bookmark-location, +;; bookmark-delete, bookmark-show-annotation: +;; Use bmkp-get-bookmark, not bookmark-get-bookmark, but in vanilla-compatible way. +;; 2021/04/13 dadams +;; Added: bmkp-get-bookmark. Removed redefinition of vanilla bookmark-get-bookmark. +;; Problem was that some 3rd-party code uses bookmark-prop-set with unfinished bookmark record +;; that has no name. Thx to Daniel Fleischer. +;; bookmark-prop-set: Added optional arg REQUIRE-NAME-P. Pass it to bmkp-get-bookmark. +;; bookmark-handle-bookmark, bookmark-default-handler, bmkp-jump-1, +;; bmkp-show-this-annotation-read-only, bmkp-edit-this-annotation, bmkp-clone-bookmark, +;; bmkp-update-autonamed-bookmark, bmkp-*-bookmark-p, bmkp-*-(c)p, bmkp-insert-bookmark-link, +;; bmkp-describe-bookmark(-internals), bmkp-bookmark-description, bmkp-handle-region-default, +;; bmkp-set-sequence-bookmark, bmkp-set-eww-bookmark-here, bmkp-jump-man, +;; bmkp-cycle(-1|-this-(file|buffer)): +;; Use bmkp-get-bookmark, not bookmark-get-bookmark. +;; 2021/03/17 dadams +;; Use buffer-string, not buffer-substring, for whole buffer. +;; 2021/03/09 dadams +;; bmkp-handle-region-default: Set region and activate it at the end. +;; 2021/03/05 dadams +;; Added: bmkp-read-buffers, bmkp-read-files. +;; bmkp(autofile|file(-this-dir))-(all|some)-tags(-regexp)-alist-only, +;; bmkp-specific-(buffers|files)-alist-only: Put property bmkp-read-arg with read-fn value. +;; bmkp-read-regexp: Made PROMPT arg optional. +;; bmkp-specific-(buffers|files)-jump(-other-window): Use bmkp-read-(buffers|files). +;; bmkp-set-autonamed-regexp-(buffer|region): Removed prompt from call to bmkp-read-regexp. +;; bmkp-annotate-bookmark-this-file/buffer, bmkp-edit-bookmark-record-file/buffer: +;; Fixed format spec. +;; 2021/03/04 dadams +;; Added bmkp-types-alist. The def is also in bookmark+-mac.el. +;; 2020/11/28 dadams +;; Removed: +;; bmkp-bookmark-type-valid-p, variable (defconst) bmkp-types-alist, and all history variables. +;; Replaced all occurrences of variable bmkp-types-alist with function bmkp-types-alist. +;; Invoke macro bmkp-define-history-variables to define history vars, after defining filter fns. +;; Moved filter-function definitions to beginning of Bookmark+ functions section. +;; bmkp-edit-tags-send: Don't use bmkp-bookmark-type-valid-p - needs to work with unknown types. +;; 2020/11/23 dadams +;; bmkp-url-target-set: Use read-from-minibuffer, not read-file-name, as fallback if no ffap. +;; TEMPORARILY work around Emacs bug #44822 with phony default URL. +;; 2020/08/30 dadams +;; Added: Info-bookmark-use-only-node-not-file-flag, redefinition of Info-bookmark-jump. +;; 2020/07/04 dadams +;; Same commands as 7/03: Remove bmkp-propertize-*-flag as part of test for getting full bmk. +;; Changed all references to `C-x p' to `C-x x'. +;; Replaced string *Bookmark List* with bookmark-bmenu-buffer (for Emacs 28). +;; bookmark-(edit|show)-annotation, bmkp-annotate-bookmark, +;; bmkp-(edit|show)-this-annotation(-read-only): +;; Replaced set make-local-variable bookmark-annotation-name by setq (auto-local in Emacs 28). +;; 2020/07/03 dadams +;; bmkp-read-bookmark-for-type: +;; Use bmkp-bookmark-record-from-name to return full bookmark from ALIST. +;; bmkp-(choose-navlist-from-bookmark-list|bookmark-file(-load|-switch)-jump| +;; snippet-to-kill-ring|desktop-delete| +;; (autonamed(-*)|dired(-*)|eww|(local|remote(-*)-|non-dir-)file(-*)|gnus|image|info|man| +;; non-file|specific-(buffers|files)|temporary|this-buffer|url|w3m|autofile)-jump*| +;; (bookmark-list|desktop|variable-list|w32-browser)-jump): +;; Use bmkp-get-bookmark-in-alist to get full bmk. +;; bmkp-jump-to-type*: Raise error if bookmark name, not record. +;; 2020/07/02 dadams +;; bmkp-specific-files-alist-only: Don't use member, use bmkp-same-file-p as equality test. +;; 2020/06/20 dadams +;; Added: bmkp-set-grep-command-bookmark. +;; 2020/01/31 dadams +;; bmkp-dired-remember-*-marks: +;; Wrap dired--unhide with with-silent-modifications. Thx to Tino Calancha. +;; 2020/01/26 dadams +;; Added: bmkp-annotated-cp. +;; 2020/01/25 dadams +;; Added: bmkp-edit-bookmark-record-file/buffer. +;; 2020/01/24 dadams +;; Added: bmkp-annotate-bookmark-this-file/buffer, bmkp-annotate-all-bookmarks-this-file/buffer. +;; 2020/01/22 dadams +;; Added: bmkp-write-alist-bookmarks-to-file, bmkp-save-bookmarks-this-file/buffer, +;; bmkp-switch-to-bookmark-file-this-file/buffer. +;; bmkp-switch-bookmark-file-create: Added optional arg SWITCH-TO-LASTP (C-u behavior). +;; bmkp-save-menu-list-state: Save also last-previous-bookmark-file. +;; 2020/01/15 dadams +;; bmkp-specific-files-alist-only: If no FILES arg and buffer is not visiting a file, use (). +;; 2020/01/12 dadams +;; Added: bmkp-make-obsolete, bmkp-make-obsolete-variable. Use everywhere instead of vanilla. +;; bookmark-completing-read, bmkp-completing-read-(1|bookmarks|lax): +;; Added optional arg USE-NIL-ALIST-P. +;; bmkp-completing-read-1: Made all args except PROMPT optional. +;; Protect defvaralias for bmkp-w3m-allow-multi-tabs-flag, for Emacs 20-21. +;; bookmark-edit-annotation: If no prefix arg, pass non-nil USE-NIL-ALIST-P arg. +;; bookmark-set: If numeric prefix arg, pass non-nil USE-NIL-ALIST-P arg. +;; bookmark-show-annotation, bmkp-retrieve-icicle-search-hits-1, bmkp-set-sequence-bookmark: +;; Pass non-nil USE-NIL-ALIST-P arg. +;; Renamed bmkp-bookmark-valid-p to bmkp-bookmark-type-valid-p. +;; bmkp-bookmark-type-valid-p: Restored missing definition (was bmkp-bookmark-type). +;; 2019/08/13 dadams +;; Added bmkp-clone-bookmark, bmkp-copy-bookmark (alias). +;; 2019/07/13 dadams +;; bookmark-edit-annotation: Added &rest _IGNORED, to accommodate vanilla change for bug #20150. +;; 2019/06/08 dadams +;; bmkp-set-kmacro-bookmark: Do not use read-kbd-macro. +;; bmkp-repeat-command: Same as in zz-repeat-command in zones.el now. +;; Require repeat.el. Bind repeat-previous-repeated-command. +;; bmkp-(next|previous)(-*)-bookmark(-*)-repeat: Removed require of repeat.el. +;; 2019/05/21 dadams +;; bmkp-dired-remember-*-marks: Updated per dired-remember-marks, for Emacs 27+. +;; 2019/05/19 dadams +;; Bind print-gensym wherever we bind print-circle. +;; 2019/05/11 dadams +;; Added bmkp-jump-to-list-button button type. Forgot it on 2019-05-02. +;; 2019/05/09 dadams +;; bmkp-this-buffer-bmenu-list: Call bookmark-maybe-load-default-file at outset. +;; 2019/05/02 dadams +;; Added: bmkp-add-jump-to-list-button. +;; bmkp-describe-bookmark(-internals): Use bmkp-add-jump-to-list-button. +;; 2019/05/01 dadams +;; Added bmkp-jump-to-list. +;; 2019/04/23 dadams +;; Added bmkp-annotation-or-bookmark-description, bmkp-propertize. +;; 2019/04/21 dadams +;; bmkp-temporary-bookmarking-mode: When enable mode reset bmkp-temporary-bookmarking-mode to nil. +;; 2019/02/18 +;; bmkp-autofile-bookmark-p, bmkp-file-target-set, bmkp-autofile-add-tags, +;; bmkp-get-autofile-bookmark: +;; Handle a directory like a file. +;; 2018/12/23 dadams +;; Added: bmkp-bookmark-type-valid-p, bmkp-buffer-bookmark-p, bmkp-buffer-alist-only. +;; Removed: bmkp-bookmark-type - use bmkp-bookmark-type-valid-p instead. +;; bmkp-edit-tags-send: Use bmkp-bookmark-type-valid-p. +;; 2018/11/22 dadams +;; bookmark-load: Return the list of bookmarks read from FILE. +;; bmkp-set-izones-bookmark: Include zone EXTRA info in bookmark record. +;; 2018/11/09 dadams +;; Removed: bmkp-line-number-at-pos (not used). +;; 2018/10/10 dadams +;; Added: bookmark-jump-other-frame. +;; 2018/09/21 dadams +;; bmkp-show-this-annotation-read-only, bmkp-edit-this-annotation, bmkp-desktop-read, +;; bmkp-jump-man, bmkp-jump-dired, bmkp-jump-to-type, bmkp-*-jump, bmkp-jump-in-navlist: +;; Use bmkp--pop-to-buffer-same-window, not switch-to-buffer. +;; bmkp-image-jump-other-window, bmkp-autofile-jump-other-window: +;; Use bmkp-select-buffer-other-window, not switch-to-buffer (typo). +;; 2018/08/30 dadams +;; Added defmacro for with-coding-priority at compile time. +;; 2018/04/24 dadams +;; Added: bmkp-cycle-eww, bmkp-cycle-eww-other-window, bmkp-next-eww-bookmark, +;; bmkp-next-eww-bookmark-other-window, bmkp-next-eww-bookmark-other-window-repeat, +;; bmkp-next-eww-bookmark-repeat, bmkp-previous-eww-bookmark, +;; bmkp-previous-eww-bookmark-other-window, bmkp-previous-eww-bookmark-other-window-repeat, +;; bmkp-previous-eww-bookmark-repeat. +;; 2018/04/22 dadams +;; Added: bmkp-bookmark-file-load-jump, bmkp-bookmark-file-switch-jump. Not bound to keys. +;; 2018/02/23 dadams +;; Changes to EWW support - thx to Charles Roelli. +;; Added: bmkp-eww-generate-buffer-flag. +;; Removed: bmkp-jump-eww-in-buffer-*eww*, bmkp-jump-eww-renaming-buffer, +;; bmkp-eww-sans-pop-to-buffer, bmkp-get-eww-mode-buffer. +;; Renamed: bmkp-eww-buffer-handling to bmkp-eww-buffer-renaming. +;; bmkp-eww-new-buf-name and bmkp-eww-jumping-p are now buffer-local. +;; bmkp-jump-eww: Respect bmkp-eww-generate-buffer-flag. Use buffer-local eww-after-render-hook. +;; Integrate code from removed functions. +;; bmkp-eww-rename-buffer: Rename to generated name if rename attempt fails and either +;; bmkp-eww-generate-buffer-flag or not bmkp-eww-jumping-p. +;; 2018/02/12 dadams +;; bookmark-write-file, bmkp-regexp-filtered-bookmark-name-alist-only: +;; Use bookmark-name-from-full-record, not car. +;; 2018/02/10 dadams +;; bookmark-rename: No need to propertize name here - done in call to bookmark-set-name. +;; bookmark-alist-from-buffer: Use bmkp-bookmark-name-from-record, not car. +;; 2017/11/27 dadams +;; bookmark-write-file: +;; Corrected change made on 2017/01/10 (fix for bug #25365). +;; Bind Lisp mode hooks to nil, to avoid inserting a Lisp file header for existing empty file. +;; 2017/10/31 dadams +;; bookmark-send-edited-annotation: test using following-char, not bmkp-looking-at-p. +;; bookmark-save: Non-nil FILE now means use FILE, regardless of PARG value. +;; 2017/10/08 dadams +;; bmkp-bookmark-description, bmkp-describe-bookmark-internals: +;; Bind print-(circle|length|level) so pp-to-string prints all. +;; 2017/07/31 dadams +;; bmkp-find-file-invoke-bookmark-if-autofile: +;; Bind bmkp-autofile-access-invokes-bookmark-flag to nil while jumping to the bookmark. +;; 2017/07/30 dadams +;; Added: bmkp-autofile-access-invokes-bookmark-flag, bmkp-find-file-invoke-bookmark-if-autofile. +;; bmkp-get-bookmark-in-alist: Use arg ALIST (was neglected). +;; 2017/07/19 dadams +;; Put back bmkp-info-cp, as an obsolete alias, temporarily. +;; 2017/07/03 dadams +;; Added: bmkp-info-position-cp, bmkp-info-sort-ignores-directories-flag. +;; Renamed: bmkp-info-cp to bmkp-info-node-name-cp. +;; bmkp-sort-comparer: Applied renaming of bmkp-info-cp. +;; bmkp-info-node-name-cp: Respect bmkp-info-sort-ignores-directories-flag (default: manual names) +;; 2017/06/26 dadams +;; Added: bmkp-kmacro-list-bookmark-p. +;; bmkp-bookmark-description: Handle bmkp-kmacro-list-bookmark-p. +;; 2017/06/25 dadams +;; Added: bmkp-set-kmacro-bookmark, bmkp-set-kmacro-list-bookmark, bmkp-jump-kmacro-list, +;; bmkp-make-kmacro-list-record. +;; 2017/05/12 dadams +;; Added: bmkp-eww-auto-bookmark-mode, bmkp-set-eww-bookmark-here, bmkp-toggle-eww-auto-type, +;; bmkp-eww-auto-type. Thx to Charles Roelli. +;; 2017/03/31 dadams +;; Added other-window versions of: bmkp-(next|previous)(TYPE)-bookmark(-repeat). +;; bmkp-autonamed-bookmark-p: +;; If BUFFER is nil then let ?B match any name - do not use current buffer for nil case. +;; bmkp-goto-position: Error now mentions buffer name, not just file. +;; bmkp-cycle: If empty bmkp-nav-alist ask before setting it to bookmark-alist. +;; 2017/02/26 dadams +;; Added: +;; bmkp-eww-rename-buffer, bmkp-eww-new-buffer-name, bmkp-eww-sans-pop-to-buffer, +;; bmkp-eww-buffer-handling (was ~bmkp-eww-allow-multiple-buffers-flag), +;; bmkp-get-eww-mode-buffer, bmkp-eww-jumping-p, bmkp-eww-new-buf-name, +;; bmkp-jump-eww-in-buffer-*eww* (was ~bmkp-jump-eww-only-one-buffer), +;; bmkp-jump-eww-renaming-buffer (was ~bmkp-jump-eww-new-buffer), bmkp-info-auto-type, +;; bmkp-info-auto-bookmark-mode, bmkp-set-info-bookmark-with-node-name, +;; bmkp-toggle-info-auto-type. +;; Removed: bmkp-eww-allow-multiple-buffers-flag, bmkp-eww-set-new-buffer-name, +;; bmkp-jump-eww-new-buffer, bmkp-jump-eww-only-one-buffer. +;; bmkp-edit-bookmark-name-and-location: Don't consider changed-buffname-p if EWW bookmark. +;; bmkp-make-eww-record: Use bmkp-eww-new-buffer-name for buffer-name field. +;; Add bmkp-eww-rename-buffer to hooks eww-after-render-hook and eww-restore-history. +;; Support EWW only for Emacs 25+, not for 24.4+. (E.g., bmkp-eww-title, bmkp-eww-url). +;; bookmark-show-all-annotations: +;; Use bookmark-maybe-load-default-file, to load bookmark file. +;; For Emacs 24+, call view-mode-enter with no args. Thx to Alan Wehmann for bug report +;; and Martin Rudalics for info about the new signature. +;; bmkp-completing-read-1: Use single default, not list, for Emacs 20-22. +;; bmkp-default-bookmark-name: +;; Ensure use a single bname, not a list of names returned by bmkp-default-lighted. +;; 2017/01/29 dadams +;; Added: bmkp-eww-title, bmkp-eww-url. +;; bookmark-set, bmkp-this-buffer-p, bmkp-make-eww-record: Use bmkp-eww-title, bmkp-eww-url. +;; 2017/01/10 dadams +;; Added: +;; bmkp-eww-allow-multiple-buffers-flag, bmkp-eww-set-new-buffer-name, bmkp-jump-eww-new-buffer, +;; bmkp-jump-eww-only-one-buffer. +;; Renamed: bmkp-replace-eww-keys-flag to bmkp-eww-replace-keys-flag, +;; bmkp-w3m-allow-multi-tabs-flag to bmkp-w3m-allow-multiple-buffers-flag, +;; bmkp-jump-w3m-new-session to bmkp-jump-w3m-new-buffer, +;; bmkp-jump-w3m-only-one-tab to bmkp-jump-w3m-only-one-buffer. Keep old as aliases. +;; bmkp-jump-eww: Dispatch to bmkp-jump-eww-(new|only-one)-buffer +;; bmkp-jump-w3m-new-buffer, bmkp-jump-w3m-only-one-buffer: Use get-buffer-create, just in case. +;; bookmark-write-file: +;; Updated per latest fix for bug #25365: insert version stamp after writing bmks. UNTESTED. +;; 2017/01/08 dadams +;; Use the term "entry", not "property" everywhere, for bookmark entries (fields). +;; 2017/01/07 dadams +;; bookmark-write-file, bookmark-load, bmkp-temporary-bookmarking-mode: +;; Use bookmark-file-coding-system (Emacs bug #25365). UNTESTED. +;; 2017/01/03 dadams +;; bookmark-location: Corrected doc string to reflect code: buffer before file. +;; 2016/12/31 dadams +;; Added: bmkp-non-invokable-bookmark-p, bmkp-non-invokable-alist-only. +;; bmkp-bookmark-description: Include non-invokable. +;; 2016/12/21 dadams +;; Added: bmkp-ffap-max-region-size, bmkp-ffap-guesser. +;; bmkp-file-target-set, bmkp-autofile-set, bmkp-autofile-(add|remove)-tags: +;; Use bmkp-ffap-guesser.bmkp-ffap-guesser, not ffap-guesser. +;; 2016/12/11 dadams +;; Added: bmkp-convert-eww-bookmarks, bmkp-replace-eww-keys-flag. +;; 2016/11/25 dadams +;; bmkp-make-function-bookmark: Added bookmark-make-record-default, to include creation date. +;; bmkp-make-sequence-record: Use 0 as position, in record. +;; bookmark-sort-flag: Replace doc string with mention that it is not used. +;; 2016/11/23 dadams +;; bookmark-save, bookmark-write-file, bookmark-load, bmkp-empty-file, bmkp-tags-in-bookmark-file, +;; bmkp-list-defuns-in-commands-file, bmkp-set-bookmark-file-bookmark, bmkp-desktop-read: +;; Raise an error if we have a directory, not a file. +;; 2016/11/18 dadams +;; Support Emacs 24.[45] too. +;; bookmark-set, bmkp-this-buffer-p, bmkp-make-eww-record: Update for Emacs 24.[45]. +;; bmkp-edit-bookmark-name-and-location: Add support for EWW. +;; bmkp-jump-eww: Create buffer *eww* if it does not exist. +;; bmkp-crosshairs-highlight: Respect bmkp-crosshairs-highlight (not really needed). +;; bmkp-eww-cp: typos: w3m -> eww. +;; 2016/11/15 dadams +;; bmkp-*eww-*, bookmark-set, bmkp-this-buffer-p, bmkp-url-bookmark-p, bmkp-url-target-set, +;; bmkp-bookmark-description: Ensure that EWW code is only for Emacs 25+. +;; 2016/11/14 dadams +;; Added: bmkp-eww-jump, bmkp-eww-jump-other-window, bmkp-eww-alist-only, bmkp-eww-bookmark-p, +;; bmkp-eww-cp, bmkp-jump-eww, bmkp-make-eww-record, bmkp-eww-history. +;; bmkp-non-file-filename: Added EWW entry. +;; bookmark-set, bmkp-this-buffer-p, bmkp-url-bookmark-p, bmkp-url-target-set, +;; bmkp-bookmark-description: Support eww-mode. +;; bmkp-url-jump(-other-window): Just use bmkp-url-alist-only. +;; 2016/10/27 dadams +;; bmkp-end-position-post-context: Typo: (point) -> ereg. +;; 2016/09/21 dadams +;; Added: bmkp-desktop-default-directory. +;; Added: desktop-full-file-name, for Emacs < 22. +;; bmkp-set-desktop-bookmark, bmkp-desktop-change-dir, bmkp-desktop-read: +;; Use bmkp-desktop-default-directory when reading or expanding file name. +;; bmkp-desktop-change-dir: Error in interactive spec too, if cannot load desktop.el. +;; 2016/09/10 dadams +;; Added: bmkp-format-spec. +;; bmkp-autoname-format: Use %B in default value. Update doc string, allowing %B. +;; bmkp-autonamed-bookmark-p: Added optional arg BUFFER. Use bmkp-format-spec. +;; bmkp-autonamed-bookmark-for-buffer-p, bmkp-autonamed-this-buffer-bookmark-p: +;; Use bmkp-autonamed-bookmark-p. +;; 2016/09/06 dadams +;; Added: bmkp-read-from-whole-string. +;; bmkp-make-function-bookmark, bmkp-set-sequence-bookmark: Use bmkp-read-from-whole-string. +;; 2016/06/23 dadams +;; bmkp-remove-all-tags, bmkp-add-tags, bmkp-set-tag-value, bmkp-remove-tags, +;; bmkp-paste-(add|paste)-tags, bmkp-autofile-add-tags: +;; Corrected doc string to say also that NO-UPDATE-P does not update mod count. +;; bookmark-store, bookmark-set, bookmark-relocate, bmkp-(url|file)-target-set, +;; bmkp-autofile-set, bmkp-autofile-remove-tags: +;; Renamed arg NO-UPDATE-P to NO-REFRESH-P. +;; 2016/06/21 dadams +;; bmkp-edit-bookmark-records-send, bmkp-set-tag-value-for-bookmarks, bmkp-rename-tag, +;; bmkp-delete-bookmarks: +;; Put bookmark-save-flag let-binding around iteration only, so modification is recorded etc. +;; 2016/05/30 dadams +;; bmkp-not-near-other-auto-idle-bmks: Corrected typo: test distance for POSITION, not point. +;; 2016/04/23 dadams +;; Added: bmkp-set-dired-bookmark-for-files. +;; 2015/10/31 dadams +;; bookmark-import-new-list: Added arg RETURN-BMKS: Return bookmarks added, if non-nil. +;; 2015/09/07 dadams +;; bmkp-some: Return cons (ELEMENT . VALUE). +;; 2015/08/16 dadams +;; Renamed bmkp-set-restrictions-bookmark to bmkp-set-izones-bookmark. +;; Renamed wide-n.el stuff to zones.el stuff. +;; 2015/08/13 dadams +;; Removed: bmkp-readable-marker. +;; bmkp-set-restrictions-bookmark: +;; Added optional args. A prefix arg prompts for VARIABLE. Use wide-n-readable-marker. +;; 2015/08/12 dadams +;; bmkp-set-restrictions-bookmark: Update for new wide-n format. +;; 2015/08/10 dadams +;; bmkp-set-restrictions-bookmark: +;; Added missing comma, to eval end marker. Corrected END: caddr now, not cddr. +;; 2015/08/06 dadams +;; bmkp-some: Fixed yesterday's fix. ;-) +;; 2015/08/05 dadams +;; bmkp-some: Fixed so it returns the first list element for which the predicate is true. +;; 2015/07/31 dadams +;; bmkp-set-restrictions-bookmark: Use new wide-n-restrictions format: (NUM BEG END). +;; 2015/06/26 dadams +;; Added: bmkp-function-alist-only. +;; 2015/06/18 dadams +;; bmkp-bookmark-description: Print location, if present, for non-file bmk. Thx Martin Oppegaard. +;; bookmark-location: Reordered - prefer buffer name to file name. +;; 2015/06/17 dadams +;; bmkp-bookmark-description: Added another \t for URL:. +;; 2015/06/15 dadams +;; Allow for POSITION in bookmarks to be nil or absent - updated bookmark-default-handler, +;; bmkp-region-bookmark-p, bmkp-handle-region-default, bmkp-goto-position, bmkp-jump-dired, +;; bmkp-not-near-other-auto-idle-bmks. +;; 2015/05/23 dadams +;; bookmark-load: Reset bmenu stuff: bmkp-bmenu-marked-bookmarks, bmkp-modified-bookmarks, +;; bmkp-flagged-bookmarks, bmkp-bmenu-omitted-bookmarks, bmkp-bmenu-filter-function. +;; 2015/04/24 dadams +;; bookmark-set: Clarified doc string wrt bookmarks that have the same name. +;; 2015/04/13 dadams +;; bmkp-temporary-bookmarking-mode: +;; Have to do bookmark-insert-file-format-version-stamp here, because make-temp-file creates the +;; file, so it satisfies file-exists-p for bookmark-write-file. +;; 2015/04/10 dadams +;; bmkp-remove-all-tags, bmkp-add-tags, bmkp-remove-tags: +;; Do not call bmkp-maybe-save-bookmarks if NO-UPDATE-P. +;; bmkp-set-tag-value-for-(navlist|bookmarks): Added optional arg MSG-P. +;; bmkp-set-tag-value-for-bookmarks: +;; Call bmkp-tags-list, bmkp-maybe-save-bookmarks, and bmkp-refresh/rebuild-menu-list. +;; bmkp-set-tag-value: +;; Pass non-nil NO-UPDATE-P to bmkp-add-tags. Unless NO-UPDATE-P, call bmkp-tags-list, +;; bmkp-maybe-save-bookmarks, and bmkp-refresh/rebuild-menu-list. +;; bmkp-remove-tags-from-all: Call bmkp-maybe-save-bookmarks and bmkp-refresh/rebuild-menu-list. +;; bmkp-rename-tag, bmkp-purge-notags-autofiles: Call bmkp-maybe-save-bookmarks. +;; 2015/03/23 dadams +;; bookmark-show-all-annotations: When in Bookmark List buffer, respect the sort order. +;; 2015/02/24 dadams +;; bmkp-get-autofile-bookmark: Corrected 2015-02-15 fix - ensure BDIR is non-nil too, before test. +;; 2015/02/22 dadams +;; Moved here from bookmark+-bmu.el: +;; bmkp-reset-bmkp-store-org-link-checking-p, bmkp-store-org-link-checking-p. +;; Advice of org-store-link (not needed for bmkp-bmenu-store-org-link). +;; bmkp-store-org-link(-1): Link type changed from bookmark-other-window to bookmark-other-win. +;; bookmark-prop-set: Added optional arg DONT-UPDATE-NAME. +;; Update bmkp-full-record property on bookmark name, unless DONT-UPDATE-NAME. +;; bmkp-record-visit, bmkp-save-new-region-location, bmkp-goto-position: +;; Use arg DONT-UPDATE-NAME in sequence of calls to bookmark-prop-set. +;; 2015/02/21 dadams +;; Added: bmkp-store-org-link, bmkp-store-org-link-1. +;; 2015/02/15 dadams +;; bmkp-get-autofile-bookmark: Corrected test for same file to use absolute file names. +;; bmkp-read-bookmark-file-default: .emacs.bmk -> ~/.emacs.bmk. +;; 2015/02/11 dadams +;; Added (redefinition of) bookmark-insert-current-bookmark for Emacs 24.3+. +;; 2015/02/08 dadams +;; Added: bmkp-properties-to-keep, bmkp-tagged-alist-only, bmkp-untagged-alist-only. +;; Renamed: bmkp-icicle-* to bmkp-icicles-*. +;; bmkp-this-buffer-bmenu-list, bmkp-navlist-bmenu-list: Restore original values in case of error. +;; bookmark-set: Do not overwrite properties listed in option bmkp-properties-to-keep. +;; bmkp-prompt-for-tags-flag: Updated doc string wrt adding, not replacing. +;; bmkp-autofile-filecache: Corrected autoload cookie (typo). +;; 2015/02/05 dadams +;; bookmark-insert-annotation: BOOKMARK can be a bookmark or its name. +;; 2015/02/03 dadams +;; bmkp-occur-target-set: Removed unused let-binding. +;; 2015/01/28 dadams +;; Added: bookmark-automatically-show-annotations, bmkp-show-this-annotation-read-only, +;; bmkp-edit-this-annotation. +;; Soft-require font-lock+.el. +;; bookmark-insert-annotation: Convert BOOKMARK input to its name. +;; bookmark-edit-annotation-mode: Bind key C-x C-q to bmkp-show-this-annotation-read-only. +;; bookmark-show-annotation-mode: Bind key C-x C-q to bmkp-edit-this-annotation. +;; bookmark-show-annotation: +;; If bookmark-automatically-show-annotations = edit then just call bookmark-edit-annotation. +;; Fix title highlighting (need font-lock+.el) and buffer-modified-p. +;; Set bookmark-annotation-name. Use `, not ', in title. +;; bookmark-edit-annotation: Manage buffer-modified-p. +;; 2015/01/17 dadams +;; Added bmkp-annotate-bookmark. +;; bookmark-show-annotation, bookmark-show-all-annotations: Made it interactive. +;; 2015/01/01 dadams +;; bookmark-default-handler, bmkp-goto-position: +;; Do not bind enable-local-variables to nil - the visit is not hidden and temporary. +;; 2014/12/18 dadams +;; bmkp-this-file-bmenu-list: Restore vars if error. +;; 2014/12/16 dadams +;; bmkp-last-specific-file-p: Use bmkp-same-file-p, not string=. +;; 2014/12/15 dadams +;; Added: bmkp-non-dir-file-jump, bmkp-non-dir-file-jump-other-window, +;; bmkp-local-non-dir-file-jump, bmkp-local-non-dir-file-jump-other-window, +;; bmkp-remote-non-dir-file-jump, bmkp-remote-non-dir-file-jump-other-window, +;; bmkp-non-dir-file-alist-only, bmkp-non-dir-file-bookmark-p, +;; bmkp-local-non-dir-file-alist-only, bmkp-local-non-dir-file-bookmark-p, +;; bmkp-remote-non-dir-file-alist-only, bmkp-remote-non-dir-file-bookmark-p. +;; bmkp-autotemp-bookmark-predicates: Added bmkp(-local|-remote)-non-dir-file-bookmark-p. +;; 2014/11/15 dadams +;; Added: bmkp-region-jump-narrow-indirect-other-window, bmkp-handle-region+narrow-indirect. +;; bmkp-jump-man: Updated for Emacs 24+, where Man-getpage-in-background returns process buffer. +;; 2014/11/14 dadams +;; bmkp-jump-1: Made arg FLIP-USE-REGION-P optional. Corrected doc string for it: it flips. +;; bmkp-snippet-to-kill-ring, bmkp-autonamed-*jump*, bmkp-temporary-jump*, bmkp-w32-browser-jump, +;; bmkp-variable-list-jump, bmkp-autofile-jump*: Removed FLIP arg (optional). +;; bmkp-region-jump*: Bind bmkp-use-region to t, and don't pass FLIP arg to bmkp-jump-1. +;; 2014/11/10 dadams +;; Added: bookmark-show-annotation-mode, (redefinition of) bookmark-default-annotation-text. +;; Renamed: bmkp-edit-annotation-mode-inherit-from to bmkp-annotation-modes-inherit-from. +;; bookmark-show-annotation: Call bookmark-show-annotation-mode, not view-mode-enter. +;; bookmark-edit-annotation-mode: +;; Use literal C-c C-M-c, since bookmark-send-edited-annotation is also bound to C-c C-c. +;; 2014/11/09/dadams +;; Added: bmkp-get-external-annotation, bmkp-visit-external-annotation. +;; bookmark-show-annotation: If the annotation is external then jump to its destination. +;; 2014/11/08 dadams +;; bmkp-bookmark-description: Corrected formatting for search-hits-p. +;; 2014/10/28 dadams +;; Added: option bmkp-edit-annotation-mode-inherit-from. +;; bookmark-edit-annotation-mode: Redefined to use define-derived-mode (per Emacs 25). +;; Use new option bmkp-edit-annotation-mode-inherit-from. +;; bookmark-send-edited-annotation: Allow derived mode (per Emacs 25). +;; bookmark-edit-annotation: +;; Call bookmark-insert-annotation. Set local var bookmark-annotation-name to arg (per E25). +;; 2014/10/27 dadams +;; Added: Redefinition of bookmark-insert-annotation. +;; bookmark-edit-annotation-mode: Use bookmark-insert-annotation. +;; 2014/08/22 dadams +;; bmkp-desktop-file-p: Redefined to not visit the file: use insert-file-contents-literally. +;; Added (not (file-directory-p filename)) condition. +;; 2014/08/21 dadams +;; Added: bmkp-annotated-bookmark-p. +;; bmkp-autofile-alist-only: Use bmkp-annotated-bookmark-p. +;; bmkp-completing-read-1: Bind icicle-bookmark-completing-p. +;; bmkp-file-this-dir-bookmark-p: Return nil if BOOKMARK is not a bookmark. +;; Use bmkp-same-file-p, not equal. +;; 2014/08/19 dadams +;; Added: bmkp-dired-wildcards-alist-only, bmkp-navlist-bookmark-p. +;; 2014/08/18 dadams +;; bmkp-this-file-p: Return nil (instead of raising error) if THIS-FILE is nil. +;; 2014/07/11 dadams +;; bookmark-load: Do not customize-save-variable if no change to bmkp-last-as-first-bookmark-file. +;; bmkp-new-bookmark-default-names: Use setq, not push, for Emacs 20. +;; 2014/07/06 dadams +;; Renamed: bmkp-show-end-of-region, bmkp-w3m-allow-multi-tabs to *-flag. +;; 2014/07/05 dadams +;; bookmark-write-file: List in file could be (), in which case cannot search backward for \n). +;; bmkp-read-bookmark-for-type: Added optional PROMPT arg. +;; bmkp-jump-snippet: Provide PROMPT to bmkp-read-bookmark-for-type. Better msg. +;; 2014/07/03 dadams +;; Added: bmkp-read-bookmark-file-default. +;; Added redefinition of bookmark-import-new-list, bookmark-maybe-rename. +;; bookmark-load: Do not set blist to value of bookmark-import-new-list. +;; bookmark-alist-from-buffer: Added optional arg do-not-propertize-p. (Not used anywhere yet.) +;; bookmark-save: Use bmkp-read-bookmark-file-default. +;; bookmark-write-file: +;; Added optional arg ADD. Do not kill FILE buffer if it existed prior to invoking function. +;; Promoted inner let-bindings print-length etc. +;; Delete contents only if file does not exist (just in case). Else *-maybe-upgrade-file-format. +;; Do not delete region if ADD. Position point depending on ADD. +;; bookmark-write-file, bookmark-default-handler, bmkp-save-menu-list-state, bmkp-goto-position, +;; bmkp-compilation-target-set: +;; Let-bind enable-local-variables around find-file-noselect. +;; bmkp-read-bookmark-file-name: Just pass DEFAULT-FILENAME to read-file-name. +;; bmkp-empty-file: Pass nil ADD arg to bookmark-write-file. +;; 2014/06/29 dadams +;; Added: bmkp-before-jump-hook, bmkp-desktop-save, bmkp-desktop-save-as-last, +;; bmkp-desktop-current-file, bmkp-desktop-jump-save-before-flag. +;; bmkp-jump-1: Run bmkp-before-jump-hook. +;; bmkp-set-desktop-bookmark: Use bmkp-desktop-save. +;; bmkp-desktop-jump: If bmkp-desktop-jump-save-before-flag then bmkp-desktop-save-as-last. +;; bmkp-desktop-kill: Updated for Emacs 24.4+. +;; 2014/06/21 dadams +;; Added: bmkp-icicle-search-hits-alist-only, bmkp-icicle-search-hits-bookmark-p, +;; bmkp-icicle-search-hits-retrieve-more, bmkp-jump-icicle-search-hits, +;; bmkp-retrieve-icicle-search-hits, bmkp-retrieve-more-icicle-search-hits, +;; bmkp-retrieve-icicle-search-hits-1, bmkp-set-icicle-search-hits-bookmark, +;; bmkp-make-icicle-search-hits-record, bmkp-unpropertized-string. +;; bmkp-bookmark-description: Handle Icicles search hits. +;; 2014/05/30 dadams +;; bmkp-set-restrictions-bookmark: Updated for new restrictions format (wide-n.el). +;; 2014/05/27 dadams +;; bmkp-describe-bookmark(-internals), bmkp-list-defuns-in-commands-file: +;; Use bmkp-with-help-window, not with-output-to-temp-buffer (Emacs 24.4+ silliness). +;; 2014/04/05 dadams +;; Removed bmkp-create-dired-bookmarks-recursive: +;; Moved to dired+.el and renamed diredp-do-bookmark-dirs-recursive. +;; 2014/04/02 dadams +;; bmkp-paste-replace-tags: Added Note to doc string about pasting an empty list of tags. +;; 2014/03/23 dadams +;; bmkp-file-target-set: Fix interactive spec (parens). +;; bmkp-file-target-set, bmkp-autofile-set, bmkp-autofile-(add|remove)-tags: +;; Soft-require ffap.el before using ffap-guesser. +;; 2014/03/10 dadams +;; bookmark-write-file: +;; Remove prop face & Icicles props, anyway (but not bothering for sequence entry of seq bmks). +;; bookmark-write-file, bmkp-edit-tags, bmkp-save-menu-list-state, bmkp-readable-p: +;; Bind print-circle to bmkp-propertize-bookmark-names-flag, not t, to avoid string reuse. +;; 2014/03/07 dadams +;; bookmark-exit-hook-internal: Do not raise error, since this is on kill-emacs-hook. +;; Bug reported: http://superuser.com/q/726057/250462. +;; 2014/01/02 dadams +;; Reverted yesterday's change. Just use cond instead of case. +;; 2014/01/01 dadams +;; Added bmkp-file-cache-ad-hack, as workaround for macro case not getting byte-compiled. +;; file-cache-add-file: Use bmkp-file-cache-ad-hack. Thx to Michael Heerdegen. +;; 2013/11/21 dadams +;; bmkp-url-target-set: Added argument NO-OVERWRITE-P. +;; bmkp-(url|file)-target-set: Numeric prefix arg means do not overwrite. N<0 means use full name. +;; 2013/11/05 dadams +;; Added: bmkp-create-dired-bookmarks-recursive. +;; bookmark-set: Added optional arg NO-UPDATE-P - pass it to bookmark-store. +;; 2013/10/29 dadams +;; Added: bmkp-pop-to-readable-marker, bmkp-readable-marker, bmkp-bookmark-set-confirm-overwrite, +;; bmkp-bookmark-set-confirms-overwrite-p. +;; bookmark-set: Ask for overwrite confirmation if plain prefix arg and bookmark exists. +;; bmkp-menu-bar-set-bookmark: Use bmkp-bookmark-set-confirm-overwrite, not bookmark-set. +;; 2013/10/07 dadams +;; bmkp-edit-bookmark-records-send: Move to line of current bmk, if only one. +;; 2013/08/09 dadams +;; Added: bmkp-read-bookmark-file-hook, bmkp-desktop-file-p. +;; Renamed: bmkp-printable-p to bmkp-readable-p. +;; bmkp-readable-p: Treat string with no text props separately. +;; bookmark-alist: Updated doc string. +;; bookmark-send-edited-annotation: looking-at -> bmkp-looking-at-p (new). +;; bookmark-load: Update blist with bookmark-import-new-list. +;; Run bmkp-read-bookmark-file-hook after reading the bookmark file. +;; bmkp-set-desktop-bookmark: Added prefix arg: sets bookmark without saving desktop file. +;; 2013/07/24 dadams +;; bmkp-new-bookmark-default-names, bookmark-make-record-default: +;; Test using (region-beginning|end), not mark function (C code and simpler). +;; 2013/07/11 dadams +;; bmkp-url-target-set: Use let* with backquote lambda instead of lexical-let*. +;; 2013/07/02 dadams +;; bmkp-snippet-bookmark-p: Typo: bmkp-snippet-to-kill-ring -> bmkp-jump-snippet. +;; bmkp-bookmark-description: Include snippet text in bookmark description (help). +;; 2013/07/01 dadams +;; bookmark-make-record-default: Fixed typo for end-position (listify). +;; bmkp-set-snippet-bookmark: Prefix arg now prompts for bookmark name. +;; 2013/06/30 dadams +;; Added: bmkp-set-snippet-bookmark, bmkp-snippet-to-kill-ring, bmkp-jump-snippet, +;; bmkp-snippet-alist-only, bmkp-snippet-bookmark-p, bmkp-snippet-history. +;; bmkp-autotemp-bookmark-predicates, bmkp-types-alist, bmkp-bookmark-type, +;; bmkp-bookmark-description: +;; Cover snippet bookmarks too. +;; bookmark-make-record-default: +;; Added optional arg NO-REGION. If non-nil then do not include end-position. +;; Set NO-CONTEXT to nil for Emacs < 24. Do not calculate FCS, RCS, FCRS, ECRS if NO-CONTEXT. +;; bmkp-make-(gnus|sequence|desktop|bookmark-file|variable-list)-record: +;; Pass NO-REGION to bookmark-make-record-default. +;; 2013/06/29 dadams +;; Added: bmkp-read-regexp, bmkp-find-tag-default-as-regexp. +;; Use bmkp-read-regexp, not read-string, everywhere for reading a regexp. +;; bmkp-bookmark-description: Ensure FILE is non-nil before using it. +;; 2013/06/10 dadams +;; bmkp-set-sequence-bookmark: Typo - bookmark-get-bookmarkp -> bookmark-get-bookmark. +;; 2013/06/02 dadams +;; bmkp-set-sequence-bookmark: Forgot to bind FUN. Thx to Michael Heerdegen. +;; 2013/05/31 dadams +;; bmkp-save-menu-list-state: Display warning, do not raise error, if write-file fails. +;; bookmark-write-file: Use display-warning, if fboundp. +;; 2013/05/28 dadams +;; Renamed: bmkp-edit-bookmark-name-and-file to bmkp-edit-bookmark-name-and-location. +;; bmkp-edit-bookmark-name-and-location: Handle location property, urls. +;; bmkp-jump-w3m-new-session, bmkp-jump-w3m-only-one-tab: Use location property, not filename. +;; Thx to Michael Heerdegen. +;; 2013/05/15 dadams +;; bmkp-*-alist-only: Make sure we call bookmark-maybe-load-default-file. +;; Moved bmkp-string-match-p to bookmark+-bmu.el. +;; Use bmkp-string-match-p instead of string-match wherever appropriate. +;; 2013/05/12 dadams +;; Added: bmkp-write-bookmark-file-hook. +;; bookmark-write-file: Run bmkp-bookmark-write-file-hook functions after writing. +;; 2013/04/19 dadams +;; bookmark-exit-hook-internal: Removed test for non-empty bookmark-alist (Emacs bug #13972). +;; 2013/04/15 dadams +;; bmkp-set-sequence-bookmark: Corrected case of adding one sequence to another. +;; bookmark-write-file: Corrected write-out of sequence bookmarks. +;; bookmark-alist-from-buffer: Better error message if read error. +;; 2013/04/14 dadams +;; Added: bmkp-wrap-bookmark-with-last-kbd-macro, bmkp-dired-remember-*-marks. +;; bookmark-write-file: If not saving propertized, remove text props for bmks in sequence bmk. +;; bmkp-edit-bookmark-record-send: +;; Raise error if bmkp-edit-bookmark-record-send was somehow reset to nil. +;; Do not reset bmkp-edit-bookmark-orig-record if read error. +;; bmkp-make-function-bookmark: +;; Prefix arg means use last-kbd-macro instead of prompting for FUNCTION. +;; Use read-from-whole-string, not read, to convert name to symbol. +;; If FUNCTION is a function or vector, do not convert it. +;; bmkp-bookmark-description: For sequence-p, remove properties from each bmk name in sequence. +;; Define bmkp-bookmark-name-from-record (no longer a defalias) with an optional UNPROPERTIZE arg. +;; bmkp-make-dired-record: Use bmkp-dired-remember-*-marks, not dired-remember-marks. +;; FUNCTION can now be a vector (a keyboard macro). Use read-from-whole-string, not read. +;; bmkp-jump-function: If function property is a vector, invoke it as a keyboard macro. +;; bmkp-set-sequence-bookmark: +;; Prefix ARG now allows for replace, in addition to append and prepend. No replace question. +;; A BOOKMARK-NAMES item can now be a bookmark, a function, or keyboard macro - or its name. +;; A BOOKMARK-NAMES item that is itself a sequence has its bookmarks spliced in. +;; Use lax as value of NAMES-ONLY-P to bmkp-completing-read-bookmarks. +;; 2013/04/12 dadams +;; Added: bmkp-sequence-alist-only. +;; bmkp-set-sequence-bookmark: Added prefix arg PREPENDP. Use bmkp-completing-read-lax. +;; Use \\ in doc strings with *-record-send. +;; bookmark-get-bookmark: A cons must also have a string car, to tell a bmk from a list of bmks. +;; bmkp-make-function-bookmark: Use bmkp-completing-read-lax for BOOKMARK-NAME. +;; 2013/04/10 dadams +;; Added: bmkp-set-sequence-bookmark, bmkp-make-sequence-record, bmkp-completing-read-bookmarks. +;; bmkp-completing-read-1: +;; Do not put DEFAULT in PROMPT if DEFAULT is "". Removed useless let-binding of DEFAULT. +;; Removed unnecessary final massaging of STR. +;; bookmark-completing-read: Mention in doc string that nil DEFAULT means return "". +;; 2013/03/29 dadams +;; bmkp-toggle-saving-bookmark-file: If neither is nil, set *-last-* to nil before toggling. +;; 2013/03/17 dadams +;; bmkp-bmenu-list-1: Do not toggle filenames unless bookmark-alist is defined (Emacs bug #13972). +;; 2013/01/07 dadams +;; bmkp-remove-all-tags, bmkp(-autofile)-(add|remove)-tags, bmkp-set-tag-value, +;; bmkp-paste-(add|replace)-tags, bmkp-(url|file)-target-set, bmkp-autofile-set: +;; Added missing NO-UPDATE-P arg for interactive spec. +;; bmkp-remove-all-tags: Moveed msg to the end. +;; bmkp-paste-replace-tags: Added sleep-for after first msg. +;; 2012/11/13 dadams +;; bmkp-sorting-description: Fixed 1st case: use ORDER only if bmkp-sort-comparer is also non-nil. +;; 2012/11/11 dadams +;; Added: bmkp-sorting-description (factored out from bmkp-msg-about-sort-order). +;; bmkp-msg-about-sort-order: Use bmkp-sorting-description. +;; bmkp-current-sort-order: Return nil if bmkp-sort-comparer is not in bmkp-sort-orders-alist. +;; 2012/11/09 dadams +;; Added: bmkp-autofile-filecache. +;; Added defadvice for file-cache-add-file. +;; bookmark-store, bmkp-url-target-set: Added optional arg NO-UPDATE-P. +;; bookmark-set, bmkp-make-function-bookmark, bmkp-url-target-set, bmkp-file-target-set: +;; Adjusted calls to bookmark-store to accommodate NO-UPDATE-P arg. +;; bmkp-make-record-for-target-file: +;; Add CREATED property for all bookmark types. Factor out the common stuff. +;; Remove any text properties from FILE arg before using it. +;; 2012/10/09 dadams +;; Made all autoload cookies explicitly load bookmark+.el(c). Should help ELPA (e.g. MELPA). +;; 2012/10/01 dadams +;; bmkp-thing-at-point: Updated per icicle-thing-at-point. Thx to Joe Bloggs. +;; 2012/09/29 dadams +;; Added redefinition of bookmark-version-control. +;; bookmark--jump-via: +;; When bmkp-use-w32-browser-p, just handle, do after-jump hook & jump-fn, and show annotation. +;; bookmark-handle-bookmark: +;; When bmkp-use-w32-browser-p, just invoke w32-browser and throw to bookmark--jump-via. +;; bookmark-write-file: Use find-file-noselect. +;; bmkp-save-menu-list-state: +;; Bind print-circle, version-control, require-final-new-line. Use find-file-noselect. +;; Copy shared bookmark lists and single strings, to avoid circular refs. +;; Raise error, not just msg, if file-error. +;; bookmark-write-file: Bind require-final-newline. +;; 2012/09/26 dadams +;; bmkp-save-menu-list-state: Use write-file, not write-region, so backups are made. +;; 2012/09/24 dadams +;; bookmark-write-file: Use write-file, not write-region, so backups are made. Emacs bug #12507. +;; 2012/09/22 dadams +;; bookmark-set: Updated handling of bmkp-auto-light-when-set for (non-)autonamed-in-buffer. +;; bmkp-autonamed-this-buffer-bookmark-p: Require that the buffer name part match also. +;; bmkp-autonamed-this-buffer-alist-only: Corrected to use bmkp-autonamed-this-buffer-bookmark-p. +;; 2012/09/11 dadams +;; bmkp-set-autonamed-bookmark-at-line: Use prefix arg for line no. Use line-beginning-position. +;; 2012/09/06 dadams +;; Added: bmkp-string-match-p. +;; 2012/08/28 dadams +;; bookmark-send-edited-annotation: Record an empty annotation as nil, not "". +;; 2012/08/21 dadams +;; Call tap-put-thing-at-point-props after load thingatpt+.el. +;; 2012/08/18 dadams +;; Invoke tap-define-aliases-wo-prefix if thingatpt+.el is loaded. +;; Added: bmkp-thing-at-point. +;; thing-at-point -> bmkp-thing-at-point, everywhere. +;; 2012/08/10 dadams +;; Info-bookmark-make-record: Updated wrt Emacs 24. +;; Renamed: old-bookmark-insert to bmkp-ORIG-bookmark-insert. +;; 2012/07/04 dadams +;; bmkp-create-variable-list-bookmark: Removed INTERACTIVEP arg to bookmark-set. +;; #'(lambda...) -> (lambda...). +;; 2012/07/02 dadams +;; bmkp-default-handler-for-file: +;; Reverted 2012/05/04 change to use lexical-let. Byte code in saved bookmark was problematic. +;; 2012/06/26 dadams +;; Wrapped require of bookmark+-mac.el in eval-when-compile. +;; 2012/06/21 dadams +;; Try to load-library bookmark+-mac. Require it only if cannot load-library. +;; 2012/06/12 dadams +;; bmkp-new-bookmark-default-names: 1. Test for DEFS at end is listp, not consp. 2. Return FNS. +;; bmkp-completing-read-1: Removed empty-input loop - caller must provide a default or handle "". +;; 2012/06/1 dadams +;; bookmark-make-record: Replace an empty bookmark name with . +;; bookmark-set, bmkp-completing-read-1: Require user to input a non-empty bookmark name. +;; bmkp-bookmark-name-member: If NAME is null, just use member. Skip any in NAMES that is null. +;; 2012/05/16 dadams +;; Added: bmkp-string-less-case-fold-p. +;; bmkp-list-all-tags: List tags alphabetically. Thx to Anders Johansson for the suggestion. +;; 2012/05/05 dadams +;; bookmark-store, bmkp-make-function-bookmark, bmkp-unomit-all, bmkp-url-target-set: +;; Added optional arg NO-MSG-P. +;; bookmark-store, bookmark-set, bmkp-record-visit, bmkp-make-function-bookmark, +;; bmkp-current-bookmark-list-state, bmkp-unomit-all, bmkp-url-target-set, bmkp-file-target-set, +;; bmkp-replace-existing-bookmark: +;; Pass NO-MSG-P to *-refresh/rebuild-menu-list, *-surreptitiously-rebuild-list, *-store. +;; 2012/05/04 dadams +;; bmkp-remove-tags, bmkp-all-tags(-regexp)-alist-only +;; bmkp(-(auto)file(-this-dir))(-(all|some)-tags)(-regexp)-alist-only, +;; bmkp-specific-(buffers|files)-alist-only, bmkp-sort-omit, bmkp-url-target-set, +;; bmkp-autofile-remove-tags. bmkp-default-handler-for-file, bmkp-set-bookmark-file-bookmark, +;; bmkp-set-desktop-bookmark, bmkp-set-variable-list-bookmark, +;; bmkp-create-variable-list-bookmark, bmkp-jump-dired, +;; bmkp-find-file-(all|some)-tags(-regexp)(-other-window): +;; Use lexical-let(*), to get closures for free vars in lambdas. +;; bmkp-regexp-filtered-(file-name|tags)-alist-only: Moved let inside lambda. +;; bmkp-make-dired-record: Use car instead of (lambda (x) (car x)). +;; 2012/05/01 dadams +;; Added: bmkp-tagged-bookmark-p (alias), bmkp-tagged-cp. +;; bmkp-(add|remove)-tags: Return negative nb-* if changed from (un)tagged to not (un)tagged. +;; bmkp-paste-replace-tags: Do not call bmkp-remove-all-tags unless there are tags to remove. +;; 2012/04/27 dadams +;; bmkp-edit-(tags|bookmark-record): Use bmkp-with-output-to-plain-temp-buffer. +;; 2012/04/18 dadams +;; Do not try to define bmkp-global-auto-idle-bookmark-mode for Emacs 21 (no define-globalized*). +;; 2012/04/16 dadams +;; bmkp-bookmark-description: List tags as strings on separate lines. +;; Add newline after annotation. +;; 2012/04/13 dadams +;; Added: bmkp-(flagged|modified)-bookmark-p, bmkp-(flagged|modified)-cp. +;; bookmark-store, bookmark-set-name, bookmark-prop-set, bmkp-edit-bookmark-record(s)-send, +;; bmkp-replace-existing-bookmark, bmkp-delete-bookmarks: +;; Use (equivalent of) eq version of add-to-list. +;; 2012/04/10 dadams +;; Added: bmkp-count-multi-mods-as-one-flag. +;; bmkp-edit-bookmark-records-send, bmkp-set-tag-value-for-bookmarks, bmkp-remove-tags-from-all, +;; bmkp-rename-tag, bmkp-purge-notags-autofiles, +;; bmkp-delete(-all)-autonamed(-for)(-this-buffer)(-no-confirm), bmkp-delete-bookmarks, +;; bmkp-delete(-all)-temporary(-bookmarks|-no-confirm): +;; Corrected bookmark-save to bookmark-save-flag in bindings to nil. +;; Use bmkp-count-multi-mods-as-one-flag for the binding. +;; 2012/04/09 dadams +;; bookmark-relocate, bmkp-edit-bookmark-records-send, bmkp-set-tag-value, bmkp-file-target-set, +;; bmkp-autofile-set: +;; Added optional arg NO-UPDATE-P. Use it to inhibit display refreshing. +;; bmkp-edit-bookmark-records-send, bmkp-set-tag-value-for-bookmarks, bmkp-remove-tags-from-all, +;; bmkp-rename-tag, bmkp-purge-notags-autofiles, delete-all-autonamed-for-this-buffer +;; bmkp-delete(-all)-temporary-(bookmarks|no-confirm), bmkp-delete-bookmarks, +;; bmkp-delete-autonamed(-this-buffer)(-no-confirm): +;; Bind bookmark-save to nil around iteration, to inhibit saving until finished. +;; bmkp-(add|remove)(-all)-tags, bmkp-paste-(add|replace)-tags, bmkp-autofile-(add|remove)-tags: +;; Swapped order of args MSGP and NO-UPDATE-P (put MSGP last). +;; bmkp-(add|remove)(-all)-tags, bmkp-autofile-(add|remove)-tags: +;; Use NO-UPDATE-P also to inhibit display refreshing. +;; bmkp-remove-tags-from-all: Pass non-nil NO-UPDATE-P arg to bmkp-remove-tags. +;; 2012/04/07 dadams +;; Added: bmkp-new-bookmark-default-names (option & function). +;; Redefine bookmark-make-record (for all Emacs versions) to use bmkp-new-bookmark-default-names. +;; bookmark-set: Use bmkp-new-bookmark-default-names (multiple defaults). +;; Moved the region-text default value stuff to fn bmkp-new-bookmark-default-names. +;; bmkp-completing-read-1: Handle a cons DEFAULT. +;; Added soft require of thingatpt+.el. +;; 2012/04/06 dadams +;; Added: bmkp-auto-idle-bookmark-min-distance, bmkp-not-near-other-auto-idle-bmks, +;; bmkp-auto-idle-bookmarks. +;; bmkp-autotemp-bookmark-predicates: +;; Changed default value to include bmkp-autonamed-bookmark(-this-buffer)-p. +;; bookmark-store: Add the bookmark to bmkp-auto-idle-bookmarks (if appropriate). +;; bookmark-delete: Remove the bookmark from bmkp-auto-idle-bookmarks. +;; bmkp-auto-idle-bookmark-mode: +;; Bind bmkp-setting-auto-idle-bmk-p. Do nothing if bmkp-not-near-other-auto-idle-bmks says so. +;; 2012/04/05 dadams +;; Added (Emacs 21+): bmkp-global-auto-idle-bookmark-mode, bmkp-turn-on-auto-idle-bookmark-mode. +;; bmkp-auto-idle-bookmark-mode (Emacs 21+): +;; Made it local: +;; Removed keyword :global, added keyword :require. +;; Timer function does nothing if the mode is not enabled (i.e., for the current buffer). +;; bmkp-auto-idle-bookmark-mode (Emacs 20): +;; Changed interactive spec to handle toggle symbol. +;; Timer function does nothing if the mode is not enabled (for the current buffer, if local). +;; Change message to mention buffer when the mode is local. +;; Removed: bmkp-auto-idle-bookmark-mode-hook. +;; Added autoload cookie for Emacs 20 defcustom for bmkp-auto-idle-bookmark-mode. +;; bmkp-auto-idle-bookmark-mode-timer: Use nil as default value. +;; bmkp-auto-idle-bookmark-mode: If timer is non-nil, set it to nil (and cancel it). +;; 2012/04/04 dadams +;; Added: bmkp-auto-idle-bookmark-mode(-delay|-hook|-lighter|-set-function), +;; bmkp-temporary-bookmarking-mode-lighter, bmkp-auto-idle-bookmark-mode-timer. +;; bmkp-temporary-bookmarking-mode: Added lighter. +;; bookmark-set: Pass INTERACTIVEP arg, not constant MSGP, to bmkp-light-(bookmarks|this-buffer). +;; 2012/04/03 dadams +;; Moved to bookmark+-bmu.el: bmkp-face-prop. +;; 2012/04/02 dadams +;; bmkp-toggle-autonamed-bookmark-set/delete, bmkp-set-autonamed-bookmark(-at-line), +;; bmkp-delete-bookmarks: +;; Made POSITION, NUMBER, ALLP optional. +;; 2012/03/18 dadams +;; Added: bmkp-modified-bookmarks, redefinition of bookmark-set-name. +;; bookmark-store, bookmark-set-name, bookmark-prop-set, bmkp-replace-existing-bookmark: +;; Add the bookmark to bmkp-modified-bookmarks. +;; bookmark-rename: Call bmkp-rename-for-marked-and-omitted-lists _after_ set new name w/ prop. +;; bookmark-save: Reset bmkp-modified-bookmarks. Call bmkp-refresh/rebuild-menu-list. +;; bmkp-rename-for-marked-and-omitted-lists: Fixed typo: marked -> omitted. +;; bmkp-edit-bookmark-name-and-file: +;; Save each of bmk name and file name only if changed (bug fix). Provide default file name. +;; If no automatic save, and modifications, ask user whether to save. +;; bmkp-edit-bookmark-records-send: +;; Add updated bookmarks to bmkp-modified-bookmarks. +;; Merge sanity-check dolist with main dolist. +;; Set bmkp-bmenu-marked-bookmarks to names in bmkp-modified-bookmarks, not in edited-bookmarks. +;; bmkp-edit-bookmark-record: Use (shallow) copy of bmkp-edit-bookmark-orig-record, not original. +;; bmkp-edit-bookmark-record-send: Add updated bookmark to bmkp-modified-bookmarks. +;; bmkp-record-visit: Let-bind bmkp-modified-bookmarks to itself, so will be restored. +;; bmkp-refresh-menu-list: Pass no FILTEREDP if no current filter (start anew). +;; bmkp-bookmark-name-member: If a name in NAMES is unpropertized, don't try to match property. +;; bmkp-replace-existing-bookmark: For propertize bookmark-current-bookmark with bmkp-full-record. +;; 2012/03/13 dadams +;; bmkp-incremental-filter-delay: +;; Use bookmark-search-delay as default value, if available. Else use 0.2 (not 0.6). +;; 2012/03/11 dadams +;; bmkp-revert-bookmark-file: Added p to interactive spec (forgot). +;; 2012/03/06 dadams +;; Added: bmkp-revert-bookmark-file. +;; bookmark-load: If bookmark-file buffer already existed, do not kill it after loading. +;; 2012/03/04 dadams +;; Added: bmkp-refresh/rebuild-menu-list. +;; bookmark-store, bookmark-send-edited-annotation, bookmark-delete, +;; bmkp-edit-bookmark-record(s)-send, bmkp-edit-tags-send, bmkp-update-autonamed-bookmark, +;; bmkp-remove(-all)-tags, bmkp-add-tags, bmkp-file-target-set, bmkp-refresh/rebuild-menu-list: +;; Use bmkp-refresh/rebuild-menu-list. +;; bookmark-load: +;; Use bmkp-refresh/rebuild-menu-list only if interactive. Do not call *-surreptitiously-*. +;; bmkp-edit-bookmark-record(s)-send: Added optional arg MSGP. Raise read error if batch. +;; bmkp-record-visit: +;; Added optional arg BATCHP. Do not bookmark-bmenu-surreptitiously-rebuild-list if BATCHP. +;; bmkp-edit-tags-send: Added optional arg BATCHP, and pass it to bmkp-record-visit. +;; bmkp-refresh-menu-list: Use bmkp-bookmark-name-from-record only when BOOKMARK is non-nil. +;; bmkp-paste-replace-tags, bmkp-(compilation|occur)-target-set-all: +;; Raise error with OK message if user cancels. +;; bmkp-purge-notags-autofiles, bmkp-delete-all-temporary-bookmarks: Added optional arg MSGP. +;; bmkp-purge-notags-autofiles, bmkp-delete-all-temporary-bookmarks, +;; bmkp-delete-temporary-no-confirm: +;; Call bmkp-refresh/rebuild-menu-list after the dolist. Inhibit refresh for bookmark-delete. +;; bmkp-jump-bookmark-file: Removed reference to current-prefix-arg: prompt only if SWITCHP. +;; bmkp-delete-all-autonamed-for-this-buffer: +;; Added optional arg MSGP. Prompt for confirmation only if MSGP. +;; bmkp-delete-autonamed-this-buffer-no-confirm: +;; Added optional arg NO-REFRESH-P. Inhibit refresh for bookmark-delete. +;; Unless NO-REFRESH-P, call bmkp-refresh/rebuild-menu-list after the dolist. +;; bmkp-delete-autonamed-no-confirm: +;; Call bmkp-delete-autonamed-this-buffer-no-confirm with NO-REFRESH-P. +;; Call bmkp-refresh/rebuild-menu-list after the dolist. +;; bmkp-delete-bookmarks: +;; Added optional arg MSGP. Prompt for confirmation only if MSGP. +;; Raise error with OK message if user cancels. +;; Call bmkp-refresh/rebuild-menu-list after the dolist. Inhibit refresh for bookmark-delete. +;; Use bmkp-this-buffer-alist-only, not bookmark-alist, for selecting bookmarks. +;; Use `...', etc. when echoing deleted bookmarks. +;; 2012/03/02 dadams +;; bookmark-load: +;; Changed last arg from NO-MSG-P to BATCHP. If non-nil, act with no prompt, saving or not. +;; If nil, prompt user whether to save before loading. If user quits with C-g, do not load. +;; bookmark-maybe-load-default-file: Pass symbol nosave, not t, as last arg to bookmark-load. +;; bmkp-switch-bookmark-file-create: Last arg is now the complement: BATCHP, not INTERACTIVEP. +;; bmkp-temporary-bookmarking-mode: Pass nosave as last arg to bookmark-load, since do save here. +;; bmkp-default-handlers-for-file-types: Added eval-when-compile to require cl.el for Emacs 20. +;; bmkp-maybe-save-bookmarks: Added optional arg SAME-COUNT-P. +;; bmkp-record-visit: Pass non-nil arg to bmkp-maybe-save-bookmarks to prevent changing mod count. +;; bookmark-store: Call bmkp-refresh-menu-list if Bookmark List is displayed. +;; bmkp-toggle-saving-bookmark-file: Added optional arg MSGP - show message only if non-nil. +;; bmkp-find-file(-other-window): Added missing FIL arg for error format string. +;; bmkp-temporary-bookmarking-mode: Pass a MSGP arg to bmkp-toggle-saving-bookmark-file. +;; 2012/02/29 dadams +;; bmkp-completing-read-lax: Bind & restore C-M-w, C-M-u, SPC, and ? (so can insert SPC, ? etc.). +;; 2012/02/28 dadams +;; bmkp-file-target-set: Call bmkp-refresh-menu-list if Bookmark List is displayed. +;; Renamed option bmkp-default-handler-associations to bmkp-default-handlers-for-file-types. +;; bmkp-default-handler-associations is NOW OBSOLETE - RENAME IT IF YOU HAVE CUSTOMIZED IT. +;; bmkp-same-file-p: Take advantage of Emacs 24 function, file-equal-p. Thx to Michael Albinus. +;; bmkp-find-file(-other-window): +;; Added optional args CREATE-AUTOFILE-P & MSGP (new arg order). Prefix arg creates bookmark. +;; Use bmkp-default-handlers-for-file-types even for files not bookmarked. +;; 2012/02/26 dadams +;; Added: bmkp-(autofile|autonamed)-history, bmkp-autofile-(all|some)-tags(-regexp)-alist-only, +;; bmkp-autofile(-(all|some)-tags(-regexp))-jump(-other-window). +;; bmkp-types-alist: Added entries for (autofile|autonamed). +;; Everywhere that read-file-name is used: +;; Bind icicle-unpropertize-completion-result-flag to t, for read-file-name. +;; No longer alias bmkp-autofile*-jump to bmkp-find-file. The *-autofile-*jump commands use +;; bmkp-read-bookmark-for-type and bmkp-jump-1, not read-file-name and find-file. +;; bmkp-find-file(-other-window): +;; Added optional args FILE MUST-EXIST-P. +;; Use read-file-name and either bookmark-jump or find-file, not just find-file (and no PRED). +;; bmkp-find-file-*-tags(-regexp)(-other-window): +;; Added optional FILE arg. +;; Use bookmark-jump, not find-file - so only autofiles with the tags are candidates. +;; Bind icicle-must-pass-after-match-predicate. Use PRED for read-file-name only if no Icicles. +;; The new bmkp-find-file* commands are bound to ... C-f, not ... a. +;; bmkp-default-handler-associations: Correct docstring: double backslashes. +;; 2012/02/21 dadams +;; bmkp-jump-to-type(-other-window): Corrected ALIST: If no HISTORY do not call *-alist-only. +;; 2012/02/20 dadams +;; bookmark-handle-bookmark: Handle, in priority, new property file-handler. +;; bookmark-default-handler: Handle new property file-handler. +;; bmkp-make-record-for-target-file: +;; Use new property file-handler, not handler, for default handler. +;; Use file-handler with play-sound-file, not handler with bmkp-sound-jump (deprecated). +;; bmkp-default-handler-for-file: Return function bmkp-user, not a lambda that applies it to file. +;; bmkp-handler-pred: +;; Return t if TYPE is handler or file-handler. Do not match a lambda that applies the handler. +;; bmkp-default-handler-associations, bookmark-alist, bmkp-jump-to-type: +;; Updated doc string to reflect new implementation of file handlers using prop file-handler. +;; 2012/02/19 dadams +;; Added: bmkp-handler-pred, bmkp-temporary-history, bmkp-w32-browser-jump. +;; bmkp-types-alist: Added bmkp-temporary-history. +;; bmkp-read-bookmark-for-type: Prepend a space before "bookmark" in prompt. +;; bmkp-jump-to-type: +;; Use lax completion. +;; When call bmkp-read-bookmark-for-type: +;; Do not append a space to TYPE name passed. +;; Pass a predicate arg returned by bmkp-handler-pred when TYPE is not a known type. +;; bmkp-*-jump(-other-window): Remove space after TYPE name passed to bmkp-read-bookmark-for-type. +;; bmkp-(specific-(buffers|files)|temporary)-jump(-other-window): +;; Pass specific HIST arg to bmkp-read-bookmark-for-type. +;; 2012/02/16 dadams +;; Updated for Emacs 24+: +;; bookmark-set: Do not set bookmark-(yank-point|current-buffer) if set. +;; bmkp-make-gnus-record: Be able to bookmark from article buffer, as well as summary buffer. +;; bmkp-jump-gnus: Go to article buffer if location field says to. +;; Use bmkp-make-gnus-record (not gnus-summary-bookmark-make-record) for Emacs 24+ also. +;; 2012/02/14 dadams +;; bmkp-set-desktop-bookmark: Provide default for read-file-name. Thx to Markus Grunwald. +;; Provide all bookmarked desktop files as Icicles proxy candidates. +;; 2012/02/08 dadams +;; bmkp-autofile-set: Use MSGP also for the case where the bookmark already exists. +;; bmkp-remove-dups: Redefined to use a hash table. +;; 2012/02/07 dadams +;; bmkp-same-file-p: Test compare-strings result using t, not non-nil. Thx to Michael Heerdegen. +;; 2012/02/04 dadams +;; Added: bmkp-tags-for-completion, bmkp-tags-in-bookmark-file. +;; Use bmkp-tags-for-completion for tags completing everywhere - updated doc strings. +;; bmkp-list-all-tags: Added args current-only-p and (optional) msgp. +;; Different prefix arg values for different behaviors. +;; bmkp-tags-list: Added optional arg current-only-p. Use bmkp-tags-for-completion by default. +;; 2012/01/20 dadams +;; bmkp(-autofile)-(add|remove)-tags(-from-all), bmkp-find-file-(all|some)-tags(-other-window), +;; bmkp(-file(-this-dir))-(all|some)-tags-jump(-other-window): +;; Let user use a prefix arg to refresh tags list. Add this info to doc string. +;; 2012/01/14 dadams +;; Corrected bmkp-same-file-p: call to compare-strings. +;; 2012/01/13 dadams +;; bmkp-same-file-p: Handle case-sensitivity for local files, at least (not yet done for remote). +;; 2012/01/08 dadams +;; Added: bmkp-autonamed-this-buffer-bookmark-p. +;; bmkp-autotemp-bookmark-predicates: Updated doc string for *-autonamed-this-buffer-bookmark-p. +;; bmkp-autonamed-bookmark-for-buffer-p: Updated doc string to mention it just checks the name. +;; bmkp-autonamed-this-buffer-alist-only: +;; Use bmkp-this-buffer-p, not bmkp-autonamed-bookmark-for-buffer-p. +;; 2011/12/30 dadams +;; Renamed bmkp-edit-bookmark to bmkp-edit-bookmark-name-and-file. +;; Added aliases: bmkp-bookmark-(data|name)-from-record. +;; Added: bmkp-get-bookmark-in-alist, bmkp-bookmark-record-from-name, +;; bmkp-edit-bookmark-records-(number|send|mode(-map)), +;; bookmark-alist-from-buffer (redefinition), bmkp-edit-bookmark-orig-record, +;; bmkp-rename-for-marked-and-omitted-lists. +;; Use new names (aliases) bmkp-bookmark-(data|name)-from-record. +;; bookmark-get-bookmark-record: Use redefinition for all Emacs versions (updated doc string). +;; bookmark-get-bookmark: Use bmkp-bookmark-record-from-name, with no MEMP check. +;; bookmark-store: Use bmkp-get-bookmark-in-alist to test whether bookmark exists. +;; Set the bookmark name also, not just the data, for an existing bookmark. +;; Unconditionally always put full bookmark on name as property bmkp-full-record. +;; bookmark-send-edited-annotation, bookmark-rename: +;; Do bookmark-bmenu-surreptitiously-rebuild-list only if no bmenu display window. +;; bookmark-rename: +;; Return OLD if if BATCHP is non-nil and NEW is nil. Do not prompt for name if BATCHP. +;; Use bmkp-rename-for-marked-and-omitted-lists (rename in those lists too). +;; Unconditionally always put full bookmark on name as property bmkp-full-record. +;; Use bmkp-bookmark-record-from-name, not bookmark-get-bookmark, to get full record. +;; bookmark-delete, bmkp-edit-bookmark-name-and-file, bmkp-edit-bookmark-record, +;; bmkp-edit-tags(-send), bmkp-toggle-autonamed-bookmark-set/delete: +;; Use bmkp-get-bookmark-in-alist, not bookmark-get-bookmark. +;; bookmark-load: Call bmkp-refresh-menu-list only if display is visible, and with NO-MSG-P arg. +;; bookmark-show-annotation: Do not raise error if not a valid bookmark. +;; bmkp-edit-bookmark-record: Record bmkp-edit-bookmark-orig-record. Strip properties from name. +;; Updated edit-buffer text. +;; bmkp-edit-bookmark-record-send: Rewrote similarly to bmkp-edit-bookmark-records-send. No args. +;; bmkp-default-bookmark-name: +;; Use bmkp-bookmark-record-from-name, not bookmark-get-bookmark, requiring membership in ALIST. +;; bmkp-save-menu-list-state, bmkp-get-tag-value: Added optional arg MSGP, and status messages. +;; bmkp-make-function-bookmark: Use bmkp-bookmark-record-from-name, not bookmark-get-bookmark. +;; bmkp-autonamed-bookmark(-for-buffer)-p: +;; Use bmkp-bookmark-name-from-record, not bookmark-get-bookmark and bookmark-name-from-*. +;; bmkp-get-tag-value, bmkp-has-tag-p: Removed unused arg MSGP. +;; bmkp-delete-bookmark-name-from-list: +;; For unpropertized DELNAME, Set BNAMES to result of delete call. +;; For propertized DELNAME, delete also unpropertized matches. +;; bmkp-(compilation|occur)-target-set-all: Do not prompt or show message unless MSGP. +;; bmkp-describe-bookmark-internals: Use a copy of the bookmark. Strip properties from name. +;; bmkp-set-autonamed-regexp-buffer: Pass MSGP, do not hardcode.n +;; Doc string improvements. +;; 2011/12/24 dadams +;; bmkp-refresh-menu-list: Added progress message. +;; bmkp-jump-bookmark-file: Pass NO-MSG-P arg to bookmark-load. +;; 2011/12/21 dadams +;; Added: bmkp-orphaned(-local|-remote)-file-(alist-only|bookmark-p), +;; bmkp-dired-wildcards-bookmark-p. +;; bookmark-load: +;; Call (bmkp-refresh-menu-list (bookmark-bmenu-bookmark)), not (bmkp-bmenu-refresh-menu-list). +;; 2011/12/19 dadams +;; bookmark-set, bmkp-handle-region-default: Use line-end-position, not end-of-line + point. +;; 2011/12/17 dadams +;; bmkp-remote-file-p: +;; If file-remote-p not available, match /...: (same as ffap-ftp-regexp). Return match. +;; bmkp-same-file-p: Redefined to use new bmkp-remote-file-p. Thx to M. Heerdegen & M. Albinus. +;; 2011/12/15 dadams +;; bmkp-dired-this-dir-bookmark-p: Use file-name-directory, in case filename has wildcards. +;; 2011/12/13 dadams +;; bmkp-handle-region-default: Limit buffer-substring-no-properties positions to point-min/max. +;; 2011/12/06 dadams +;; bmkp-last-as-first-bookmark-file: +;; Removed autoload cookie to avoid void-variable error for bookmark-default-file. +;; bmkp-edit-bookmark, bookmark-rename: Use bmkp-completing-read-lax, not read-from-minibuffer. +;; 2011/12/05 dadams +;; bmkp-this-buffer-p: +;; Do not use buffer-file-name (for Dired). Wrap bookmark-buffer-file-name with condition-case. +;; bookmark-save: Swap write order, so last message is about the bookmark file, not customize. +;; 2011/12/03 dadams +;; Renamed: bmkp-use-bookmark-file-create to bmkp-switch-bookmark-file-create. +;; Added: bmkp-last-as-first-bookmark-file, bookmark-maybe-load-default-file (redefinition), +;; bookmarks-already-loaded (redefinition), bmkp-default-bookmark-file. +;; bookmark-save: Update and save bmkp-last-as-first-bookmark-file. +;; bookmark-load: New default for reading file name, and require an existing file (match). +;; Update and save bmkp-last-as-first-bookmark-file. Update bmkp-sorted-alist. +;; bmkp-switch-bookmark-file (no longer used): New default for reading file name. +;; bmkp-switch-bookmark-file-create: Added optional arg INTERACTIVEP. New default for reading +;; file name. Use bookmark-load, not bmkp-switch-bookmark-file. Require confirmation only for +;; new, empty file. Added final message. +;; bmkp-switch-to-last-bookmark-file: Use bmkp-last-as-first-bookmark-file as first fallback. +;; bmkp-set-bookmark-file-bookmark: Use bmkp-read-bookmark-file-name, not read-file-name. +;; New default for reading file name. +;; bmkp-temporary-bookmarking-mode: Use bookmark-load, not bmkp-switch-bookmark-file. +;; Removed: bookmark-maybe-message. Use only message now, not bookmark-maybe-message. +;; bmkp-autofile-set: For Emacs 23.3+, provide multiple defaults for file name. +;; 2011/11/30 dadams +;; bmkp-same-file-p: Avoid having Tramp prompt for passwords, when possible. Thx to M. Heerdegen. +;; bmkp-toggle-autotemp-on-set: Removed ARG (copy/paste typos). +;; 2011/11/28 dadams +;; bmkp-set-bookmark-file-bookmark: Prompt user for bookmark name here, to make clear what it is. +;; 2011/11/27 dadams +;; bookmark-write-file: If write error, do not overwrite message. And show error msg for 4 sec. +;; 2011/11/18 dadams +;; Renamed: bmkp-bookmark-image-bookmark-p to bmkp-image-bookmark-p. +;; Added: bmkp-image-alist-only, bmkp-image-jump(-other-window), bmkp-image-history. +;; bookmark-handle-bookmark: If bmk has handler but it's not a function, use default handler. +;; bmkp-autotemp-bookmark-predicates: Update doc string to include bmkp-image-bookmark-p. +;; bmkp-types-alist: Added entry for images. +;; 2011/11/15 dadams +;; bookmark-relocate: Redefine without using old-*. Update Dired location too. +;; Added: bmkp-cycle-this-file(/buffer)(-other-window), +;; bmkp-(next|previous)-bookmark-this-file(/buffer)(-repeat), +;; bmkp-this-file(/buffer)-bmenu-list, bmkp-this-file/buffer-alist-only. +;; Renamed bmkp-this-buffer-cycle-sort-comparer to bmkp-this-file/buffer-cycle-sort-comparer. +;; bmkp-this-buffer-p: Return nil if bookmark has a file diff from buffer. +;; bmkp-this-file-p: +;; Ensure bmkp-file-bookmark-p and bookmark-buffer-file-name. Use bmkp-same-file-p. +;; 2011/11/09 dadams +;; bmkp-jump-dired, bmkp-jump-man: Added bmkp-select-buffer-other-window to other-window fns. +;; 2011/11/08 dadams +;; bmkp-edit-bookmark: For new file name, use read-file-name, not read-from-minibuffer. +;; 2011/11/03 dadams +;; Renamed: bmkp-autoname-bookmark to bmkp-autoname-bookmark-function-default. +;; 2011/11/01 dadams +;; Added: bmkp-temporary-jump(-other-window). +;; bmkp-bookmark-description: Title now indicates whether temporary. +;; 2011/10/31 dadams +;; Added: bmkp-toggle-autotemp-on-set, bmkp-autotemp-all-when-set-p. +;; bookmark-set: If bmkp-autotemp-all-when-set-p call bmkp-make-bookmark-temporary. +;; 2011/10/28 dadams +;; Added: bmkp-delete-temporary-no-confirm. +;; bmkp-delete-all-temporary-bookmarks: Rewrote (it was just a stub). +;; bmkp-bmenu-menubar-menu: +;; Added: bmkp-temporary-bookmarking-mode, bmkp-delete-all-temporary-bookmarks, +;; bmkp-bmenu-toggle-marked-temporary/savable. +;; bmkp-bmenu-show-menu: Added: bmkp-bmenu-show-only-temporary. +;; bmkp-bmenu-mark-menu: +;; Added: bmkp-bmenu-mark-temporary-bookmarks, bmkp-bmenu-mark-autonamed-bookmarks. +;; bmkp-bmenu-mouse-3-menu: Added: bmkp-bmenu-toggle-temporary. +;; bookmark-bmenu-mode: Updated doc string. +;; 2011/10/27 dadams +;; Added: bmkp-autotemp-bookmark-predicates, bmkp-temporary-bookmarking-mode(-hook), +;; bmkp-delete-all-temporary-bookmarks, bmkp-make-bookmark-(savable|temporary), +;; bmkp-toggle-temporary-bookmark, bmkp-temporary-alist-only, bmkp-temporary-bookmark-p. +;; bookmark-set: Make bookmark temporary, if bmkp-autotemp-bookmark-predicates says to. +;; bookmark-write-file: Do not save temporary bookmarks (bmkp-temporary-bookmark-p). +;; 2011/10/25 dadams +;; bmkp-empty-file: Added optional arg CONFIRMP. By default, no confirmation if not interactive. +;; 2011/08/09 dadams +;; Bind icicle-unpropertize-completion-result-flag to t for all calls to completing-read. +;; 2011/08/07 dadams +;; Added: bmkp-guess-default-handler-for-file-flag, bmkp-file-bookmark-handlers. +;; bmkp-file-bookmark-p: Use bmkp-file-bookmark-handlers, which means also image-bookmark-jump. +;; bmkp-make-record-for-target-file (need to keep in sync with diredp-bookmark): +;; Instead of image-bookmark-make-record, use explicit function that includes file and type. +;; bmkp-default-handler-for-file: +;; Use bmkp-guess-default only if bmkp-guess-default-handler-for-file-flag is non-nil. +;; bmkp-default-handler-associations: Updated doc string. +;; 2011/08/05 dadams +;; bmkp-file-bookmark-p: Allow handler to be bmkp-default-handler-for-file, e.g. for image files. +;; bmkp-all-tags-alist-only: Corrected. +;; bmkp-refresh-menu-list: Ensure BOOKMARK is a string. +;; bmkp-every: Removed unused binding. +;; 2011/05/08 dadams +;; Just put some definitions in alphabetic order - no real change. +;; 2011/04/25 dadams +;; bmkp-bookmark-description: Added optional arg NO-IMAGE. +;; bmkp-url-target-set: Protect url-get-url-at-point with fboundp. +;; bmkp-(file-target|autofile)-set, bmkp-autofile-(add|remove)-tags: +;; Added buffer-file-name as a default possibility. Removed URL functions for that purpose. +;; 2011/04/24 dadams +;; Added: bmkp-purge-notags-autofiles. +;; bookmark-delete: Redefined to accept either bookmark or name as arg. +;; bmkp-(url|file|compilation|occur)-target-set(-all), bmkp-autofile-(set|(add|remove)-tags): +;; Removed optional args when read prefix. +;; bmkp-occur-target-set-all: Made PREFIX arg optional too. +;; Added some missing autoload cookies. Removed some from non-def sexps. +;; 2011/04/21 dadams +;; Added: bmkp-copied-tags, bmkp-copy-tags, bmkp-paste-add-tags, bmkp-paste-replace-tags.. +;; 2011/04/20 dadams +;; bmkp-remove-all-tags: Added optional arg no-cache-update-p. +;; 2011/04/19 dadams +;; bmkp-make-record-for-target-file: Fixed backquotes on lambdas. +;; 2011/04/17 dadams +;; bmkp-edit-tags: Do not apply bmkp-full-tag to the tags. +;; 2011/04/16 dadams +;; Added: bmkp-edit-tags(-send|-mode(-map)), bmkp-return-buffer. +;; bookmark-(rename|relocate|send-edited-annotation), bmkp-update-autonamed-bookmark, +;; bmkp-(add|remove(-all)-tags: +;; Wrap with-current-buffer around bmkp-refresh-menu-list. +;; bookmark-(store|rename|write-file): Test emacs-major-version, not just (boundp 'print-circle). +;; bmkp-autofile-add-tags: Fix interactive args - forgot to include DIR arg (= nil). +;; 2011/04/15 dadams +;; Added: bmkp-autofile-alist-only, bmkp-autofile-bookmark-p. +;; 2011/04/13 dadams +;; Added: bmkp-autofile-jump(-other-window) (aliases), bmkp-find-file(-other-window). +;; bmkp-find-file-(all|some)-tags(-regexp)(-other-window): Bind use-file-dialog to nil. +;; 2011/04/12 +;; Added: bmkp-bookmark-name-member, bmkp-names-same-bookmark-p, bmkp-sort-omit, +;; bmkp-remove-omitted, bmkp-delete-bookmark-name-from-list, bmkp-bookmark-a-file (alias), +;; bmkp-autofile-(add|remove)-tags, bmkp-(un)tag-a-file (aliases), +;; bmkp-get-autofile-bookmark, bmkp-find-file-(all|some)-tags(-regexp)(-other-window). +;; Removed: bmkp-remove-assoc-dups, bmkp-sort-and-remove-dups. +;; Applied renaming: bmkp-bmenu-omitted-list to bmkp-bmenu-omitted-bookmarks. +;; bookmark-store: Redefine for all Emacs versions now: +;; Put the bookmark on the name as property bmkp-full-record. Use bmkp-maybe-save-bookmarks. +;; Return the bookmark. +;; bookmark-get-bookmark: Redefine for all Emacs versions now: +;; If BOOKMARK is a bookmark-name string that has property bmkp-full-record, return that value. +;; bookmark-send-edited-annotation: Make sure it's the annotation buffer that gets killed. +;; bookmark-default-handler: Return nil, like vanilla (but why?). +;; bookmark-location: Pass full bookmark to the various "get" functions. +;; bookmark-rename: Put bmkp-full-record property on new name. +;; bookmark-delete: +;; Use bmkp-delete-bookmark-name-from-list: If name has bmkp-full-record property, use that +;; with name to find bookmark to delete. +;; Pass full bookmark to unlight. +;; bmkp-edit-bookmark: Save if either is non-empty, not if both are. Thx to Michael Heerdegen. +;; bmkp-edit-bookmark-record: Bind print-circle to t around pp. +;; bmkp-default-bookmark-name: +;; Use bookmark-name-from-full-record plus bookmark-get-bookmark, not assoc. +;; If BNAME is nil (no default) then do not try to look it up in alist. +;; bookmark-write-file: Unpropertize only for Emacs 20 or nil bmkp-propertize-bookmark-names-flag. +;; Bind print-circle to t around pp. +;; bmkp-save-menu-list-state: Make it interactive (a command). Bind print-circle. +;; Use bmkp-maybe-unpropertize-bookmark-names on alists and name lists. +;; Bind print-circle to t around pp. +;; bmkp-unomit-all: Use bmkp-delete-bookmark-name-from-list, not delete. +;; bmkp-dired-this-dir-bookmark-p: Use bmkp-same-file-p, not string=. +;; bmkp-url-target-set, bmkp-replace-existing-bookmark:: Return the bookmark. +;; bmkp-file-target-set: Return bookmark. Added arg MSGP: msg if no file yet. +;; bmkp-autofile-set: +;; Added DIR arg and MSGP arg: msg if no file yet. Return the bookmark. +;; If read absolute file name, create bmk in its dir, not in default-directory. Else use DIR. +;; Use bmkp-get-autofile-bookmark, so uses bmkp-same-file-p for each file part (not equal). +;; bmkp-marked-bookmark-p, bmkp-omitted-bookmark-p: Use bmkp-bookmark-name-member, not member. +;; bookmark-location: Pass full bookmark to the various "get" functions. +;; bmkp-choose-navlist-from-bookmark-list, bmkp-cycle-this-buffer: +;; Use bmkp-sort-omit, not bmkp-sort-and-remove-dups. +;; bmkp-bookmark-description, bmkp-describe-bookmark-internals: Add Bookmark `' to title. +;; bmkp-make-bookmark-list-record: Use bmkp-maybe-unpropertize-bookmark-names on lists. +;; bmkp-printable-p: Bind print-circle to t around prin1. +;; bmkp-delete-autonamed(-this-buffer)-no-confirm: +;; Do nothing if bookmarks not loaded. Thx to Christoph Scholtes. +;; 2011/04/03 dadams +;; Added: bmkp-make-record-for-target-file, bmkp-replace-existing-bookmark (not used). +;; bmkp-file-this-dir-bookmark-p: Corrected it to compare directory to default-directory. +;; bmkp-file-target-set: Added arg NO-OVERWRITE (pass to bookmark-store). +;; Use (new) bmkp-make-record-for-target-file. +;; bmkp-autofile-set: Do nothing if bookmark with same name, file and dir exists. +;; Else create one, even if the bookmark name is the same. +;; You can have multiple autofile bookmarks with the same name (diff files). +;; 2011/04/02 dadams +;; Added: bmkp-autofile-set, bmkp-file-this-dir-(all|some)-tags(-regexp)-jump(-other-window), +;; bmkp-file-this-dir-(all|some)-tags(-regexp)-alist-only. +;; 2011/04/01 dadams +;; Moved key and menu bindings to (new) bookmark+-key.el. +;; Added: bmkp-(dired|file)-this-dir-alist-only, bmkp-(dired|file)-this-dir-bookmark-p, +;; bmkp-file-this-dir-jump(-other-window). +;; Renamed: bmkp-dired-jump-current(*) to bmkp-dired-this-dir-jump(*). +;; bmkp-dired-this-dir-jump(-other-window): Use bmkp-dired-this-dir-alist-only. +;; bmkp-types-alist: Added (dired|file)-this-dir. +;; Bound bmkp-(dired|file)-this-dir-jump to C-d and C-f in bookmark-jump(-other-window)-map. +;; bmkp-jump-dired, bmkp-jump-man: Treat null bmkp-jump-display-function as display-buffer. +;; 2011/03/26 dadams +;; Added: bmkp-file-(all|some)-tags(-regexp)-(alist-only|jump(-other-window)). +;; bmkp-jump-menu: Added the new commands, but not Emacs 20, to avoid crash if byte-compiled. +;; bmkp-bookmark-jump*-other-window: Simplified doc strings - refer to same-window version. +;; 2011/03/17 dadams +;; bmkp-describe-bookmark: Added 10-pixel margin around thumbnail image. +;; 2011/03/11 dadams +;; Protect use of mouse-wheel-*-event with boundp. Thx to Chris Poole. +;; 2011/03/04 dadams +;; bmkp-bookmark-description, bmkp-describe-bookmark: Added clickable thumbnail to the help. +;; bmkp-bookmark-description: Split file name into dir & relname, so shorter line, in help. +;; 2011/03/03 dadams +;; Added: bmkp-all-exif-data, bmkp-bookmark-image-bookmark-p. +;; bmkp-bookmark-description: Handle image EXIF data. +;; 2011/01/03 dadams +;; Removed autoload cookies from non def* sexps and from define-key and define-prefix-command. +;; Added some missing autoload cookies for commands, in particular redefined standard commands. +;; 2010/12/10 dadams +;; Added defalias for bookmark-name-from(-full)-record, to fix gratuitous Emacs name change. +;; 2010/10/22 dadams +;; Uncommented key bindings for mouse wheel, since Emacs bug #6256 has now been fixed. +;; bmkp-repeat-command: Don't bother to let-bind repeat-previous-repeated-command, +;; and use setq, not let, for last-repeatable-command. Thx to Stefan Monnier. +;; 2010/09/28 dadams +;; Added: bmkp-delete-autonamed(-this-buffer)-no-confirm. +;; 2010/09/25 dadams +;; Added: option bmkp-default-bookmark-name, bmkp-annotated-alist-only. +;; Added: bmkp-(next|previous)-*(-repeat), using macro bmkp-define-next+prev-cycle-commands. +;; bmkp-default-bookmark-name: Respect option. +;; bookmark-edit-annotation-mode, bookmark-edit-annotation: +;; Use bmkp-annotated-alist-only (and new bmkp-default-bookmark-name). +;; bookmark-send-edited-annotation: +;; End in orig buffer, not bmenu buffer. Delete edit window. Thx to Joe Bloggs. +;; 2010/09/24 dadams +;; Added: bmkp-autonamed(-this-buffer)-jump(-other-window). Bound to C-x j # (#|.) and menus. +;; Added, using bmkp-define-cycle-command: +;; bmkp-cycle-(autonamed|bookmark-list|desktop|dired|gnus|info|lighted|(local-|remote-)file| +;; man|non-file|remote-file|specific-(buffers|files)|variable-list|url) +;; (-other-window). +;; Added redefinitions: bookmark-edit-annotation(-mode). +;; Renamed: *varlist* to *variable-list*. +;; bmkp-autoname-format: Added ^ to anchor numeral at beginning. +;; bookmark--jump-via: Don't update autonamed if using w32 association. +;; bmkp-update-autonamed-bookmark: bmkp-refresh-menu-list only if buffer list is displayed. +;; *-(relocate|rename), *-update-autonamed-bookmark, *-remove-all-tags, *-(add|remove)-tags: +;; Don't create bookmark-list buffer if doesn't exist. +;; bookmark-show-(annotation|all-annotations): Restore selected window and frame focus. +;; bmkp-completing-read-(buffer|file)-name: Added optional NO-DEFAULT-P arg. +;; bmkp-describe-bookmark: Default to highlighted bookmarks on line, if there are any. +;; bmkp-specific-(buffers|files)-jump(-other-window): Allow empty input, to end loop. +;; bmkp-cycle: Ensure bmkp-current-nav-bookmark is a bookmark, else redefine. Use %9d, not %d. +;; bmkp-cycle-other-window: Added optional STARTOVERP arg here too. +;; 2010/09/20 dadams +;; bmkp-choose-navlist-of-type: Empty input means "any". +;; 2010/09/16 dadams +;; bmkp-read-bookmark-file-name: +;; Removed extra default-filename in call to read-file-name. Thx to Pedro Insua. +;; 2010/08/22 dadams +;; Added: bmkp-regexp-filtered-annotation-alist-only. +;; 2010/08/20 dadams +;; Added: bmkp-read-bookmark-file-name. +;; bookmark-save, bookmark-load, bmkp-switch-bookmark-file, bmkp-use-bookmark-file-create: +;; Use bmkp-read-bookmark-file-name. +;; 2010/08/19 dadams +;; Require gnus-sum.el when compile (for macro). Thx to S. Nemec. +;; 2010/08/18 dadams +;; Removed eval-when-compile for bookmark+-lit.el. +;; Replaced defvar of bmkp-edit-bookmark-record-mode-map with a define-key after derived mode. +;; 2010/08/17 dadams +;; bmkp-edit-bookmark: Made interactive. Bound to C-x p E. Added optional INTERNALP arg. +;; bmkp-info-bookmark-p: Return nil if a different handler. +;; 2010/08/15 dadams +;; Moved bmkp-define-file-sort-predicate, bmkp-menu-bar-make-toggle to bookmark+-mac.el. +;; Require: bookmark.el, bookmark+-mac.el. +;; Require for compile: bookmark+-bmu.el, bookmark+-lit.el (soft). +;; Ensure this file is loaded before compiling. +;; bmkp-set-bookmark-file-bookmark: Added missing arg for error format string. +;; 2010/08/08 dadams +;; bookmark-jump: Added optional arg DISPLAY-FUNCTION (Emacs 24). +;; bookmark-handle-bookmark: +;; Move non-default handler call outside condition-case. +;; Updated for Emacs 24: Use error condition bookmark-error-no-filename. Added props for it. +;; bookmark-default-handler: Updated for Emacs 24: +;; Signal condition bookmark-error-no-filename, not file-error, and pass (stringp FILE). +;; bookmark-make-record-default: Added optional args NO-CONTEXT, POSITION (Emacs 24), and VISITS. +;; bookmark-load: Updated for Emacs 24: Wrap with abbreviate-file-name. +;; bmkp-jump-1: Allow arg to be a bookmark or its name. +;; bmkp-gnus-bookmark-p: Updated for Emacs 24: Added gnus-summary-bookmark-jump. +;; bmkp-jump-gnus: Different gnus-fetch-group call for Emacs 20, 21. +;; bmkp-make-(desktop|varlist|bookmark-(file|list))-record: Call *-record-default with NO-CONTEXT. +;; w3m-current-title: Use w3m-current-title as bookmark name. +;; bmkp-w3m-set-new-buffer-name, bmkp-jump-w3m*: Require w3m. +;; bmkp-make-gnus-record: Get bookmark name from gnus-summary-article-header. +;; Update for Emacs 24: Bypass bmkp specific Gnus, man, and woman code. +;; 2010/08/06 dadams +;; Added (and bound the commands): +;; bmkp-(compilation|occur)-target-set(-all), bmkp-(file|url)-target-set, +;; bmkp-default-handler-associations, bmkp-compilation-file+line-at, +;; bmkp-default-handler-(for-file|user), bmkp-sound-jump. +;; bmkp-occur-create-autonamed-bookmarks: Do not define it for Emacs < 22. Protect wrt POS, BUF. +;; Added to Bookmark menu: bmkp-(file|url)-target-set, bmkp-set-(bookmark-file|desktop)-bookmark. +;; 2010/08/04 dadams +;; bmkp-edit-bookmark: Use new bookmark name for update of dired-directory. Thx to Kai Tetzlaff. +;; 2010/08/03 dadams +;; bmkp-make-url-browse-record: Remove text properties from URL arg. +;; 2010/07/17 dadams +;; Added: bmkp-url-jump-(other-window), bmkp-url(-browse)-(alist-only|bookmark-p), bmkp-url-cp, +;; bmkp-url-history, bmkp-make-url-browse-record, bmkp-jump-url-browse. +;; bmkp-sort-comparer: Use bmkp-url-cp, not bmkp-w3m-cp. +;; bmkp-types-alist: w3m -> url. +;; bookmark-alist: Updated doc string to mention LOCATION. W3M -> URL. +;; bmkp-bookmark-description: Treat URL. Set no-position-p depending on start. +;; Bind bmkp-url-jump*. Replace W3M by URL in menu items. +;; 2010/07/14 dadams +;; Created from bookmark+.el code. + +;;;(@* "CHANGE LOG FOR `bookmark+-bmu.el'") +;; +;; 2022/01/14 dadams +;; bmkp-bmenu-edit-marked: Enable undo inside with-current-buffer (not significant). +;; 2021/09/19 dadams +;; Moved defgroup from here to bookmark+.el, for new defcustom bmkp-bmenu-buffer. +;; Everywhere: Use bmkp-bmenu-buffer, not vanilla bookmark-bmenu-buffer. +;; bmkp-bmenu-barf-if-not-in-menu-list: Test mode with derived-mode-p; don't test buffer name. +;; 2021/08/18 dadams +;; Applied renaming of bmkp-auto-idle-bookmark-mode to bmkp-automatic-bookmark-mode. +;; 2021/04/16 dadams +;; bookmark-bmenu-execute-deletions: +;; Use bmkp-get-bookmark, not bookmark-get-bookmark, but in vanilla-compatible way. +;; bmkp-bmenu-make-sequence-from-marked, bmkp-bmenu-remove-tags-from-marked, +;; bmkp-bmenu-propertize-item, bmkp-bmenu-marked-or-this-or-all: +;; Use bmkp-get-bookmark, not bookmark-get-bookmark. +;; 2021/03/05 dadams +;; Face bmkp-no-local: changed default to orange background, from yellow foreground. +;; 2021/03/04 dadams +;; bmkp-bmenu-describe-marked: Typo - bmkp-describe-bookmark-marked -> bmkp-bmenu-describe-marked. +;; 2020/12/29 dadams +;; Wrap soft-require of menu-bar+.el in null condition-case, because it soft-requires Bookmark+. +;; 2020/11/27 dadams +;; bmkp-bmenu-define-command, bmkp-bmenu-define-full-snapshot-command: +;; Use copy-sequence for lists, because some code modifies the list structure. +;; If command already defined then prompt to overwrite its definition (replace all existing). +;; bmkp-bmenu-define-full-snapshot-command: +;; Bind bookmark-alist to non-nil bmkp-latest-bookmark-alist. NB: Contradicts 2015-02-22 change. +;; 2020/11/26 dadams +;; bmkp-bmenu-read-filter-input: +;; Set, don't bind, bmkp-bmenu-filter-(title|function). Restore them and the pattern, if C-g. +;; 2020/11/06 dadams +;; bmkp-bmenu-read-filter-input: +;; Bind prefix-command-echo-keystrokes-functions to nil. See Emacs bug #44500. +;; 2020/07/04 dadams +;; Changed all references to `C-x p' to `C-x x'. +;; Replaced string *Bookmark List* with bookmark-bmenu-buffer (for Emacs 28). +;; 2020/01/26 dadams +;; Added: bmkp-bmenu-sort-annotated-before-unannotated (bound to s a). +;; 2020/01/22 dadams +;; bookmark-bmenu-list: Restore bookmark-bmenu-list to saved value, last-previous-bookmark-file. +;; bookmark-bmenu-mode: Added to doc: *-(switch-to-bookmark-file|save-bookmarks)-this-file/buffer. +;; bmkp-bmenu-bookmark-file-menu: Added bmkp-switch(-to-last)-bookmark-file(-create). Reordered. +;; 2020/01/15 dadams +;; Added: bmkp-bmenu-edit-annotations-for-marked. +;; Bind bookmark-bmenu-(show|edit)-annotation, bookmark-bmenu-show-all-annotations, +;; bmkp-bmenu-edit-annotations-for-marked to new prefix key a (a, e, A, >) and in +;; bmkp-bmenu-(edit|show)-menu and bmkp-bmenu-mouse-3-menu. +;; No longer bind bmkp-bmenu-show-or-edit-annotation. +;; 2019/10/29 dadams +;; bookmark-bmenu-relocate: Ensure that arg to bookmark-relocate is not nil. +;; bookmark-bmenu-bookmark: Mention in doc: nil return if no bookmark. +;; bookmark-bmenu-show-annotation, bmkp-bmenu-w32-open-with-mouse: Raise error if no bookmark. +;; bmkp-bmenu-show-menu: Enable bookmark-bmenu-show-annotation only if there is a bookmark. +;; 2019/08/13 dadams +;; Added bmkp-bmenu-clone-bookmark, bmkp-bmenu-copy-bookmark (alias). Bound to M-n in bmk list. +;; Added it to bmkp-bmenu-menubar-menu, bmkp-bmenu-mouse-3-menu. +;; 2019/08/09 dadams +;; bmkp-file-handler: Changed default to LightBlue background. +;; 2019/05/19 dadams +;; Bind print-gensym wherever we bind print-circle. +;; 2019/04/23 dadams +;; Added bmkp-bmenu-edit-menu. +;; Moved bmkp-bmenu-edit-marked to bmkp-bmenu-edit-menu from main Bookmark+ menu. +;; bmkp-bmenu-show-menu: Added bookmark-bmenu-show-annotation. +;; 2018/11/24 dadams +;; bookmark-bmenu-other-(window|frame): +;; Added missing bookmark-name arg to b-j-o-(window|frame). Thx to Alan Wehmann. +;; Added: bmkp-bmenu-load-marking, bmkp-bmenu-load-marking-unmark-first. +;; bmkp-bmenu-(bookmark-file|mark)-menu: Added bmkp-bmenu-load-marking(-unmark-first). +;; 2018/10/10 dadams +;; Added: bookmark-bmenu-other-frame. +;; bookmark-bmenu-mode: Added bookmark-bmenu-other-frame to doc string. +;; 2018/09/21 dadams +;; Added: bmkp--pop-to-buffer-same-window. (Added also to bookmark+-lit.el.) +;; bookmark-bmenu-2-window, bookmark-bmenu-this-window: +;; Use bmkp--pop-to-buffer-same-window, not switch-to-buffer. +;; 2018/08/28 dadams +;; bmkp-bmenu-read-filter-input: Do not pass non-characterp value to text-char-description. +;; 2017/10/27 dadams +;; bookmark-bmenu-mode: Added to doc string: bmkp-bmenu-paste-(add|replace)-tags. +;; 2017/10/14 dadams +;; All EWW stuff is for Emacs 25+, not Emacs 24.4+. +;; 2017/10/08 dadams +;; bmkp-bmenu-describe-marked: Bind print-(circle|length|level) so pp-to-string prints all. +;; 2017/07/03 dadams +;; Added: bmkp-bmenu-sort-by-Info-position. +;; Renamed bmkp-bmenu-sort-by-Info-location to bmkp-bmenu-sort-by-Info-node-name. +;; bookmark-bmenu-mode: Updated doc string for Info-bookmark sorting. +;; bmkp-bmenu-sort-by-bookmark-type, bmkp-bmenu-sort-by-Info-node-name: +;; Applied renaming of bmkp-info-cp to bmkp-info-node-name-cp. +;; Bind bmkp-bmenu-sort-by-Info-position to s I. +;; bmkp-bmenu-sort-menu: +;; Added bmkp-bmenu-sort-by-Info-position. Renamed By Info Node to By Info Node Name. +;; 2017/03/30 dadams +;; bmkp-bmenu-mark-*-bookmarks: +;; Added optional arg MSGP. Pass it to bmkp-bmenu-mark-bookmarks-satisfying. +;; bmkp-bmenu-mark-(orphaned-local-)file-bookmarks: Made argument ARG optional. +;; bmkp-bmenu-mark-bookmarks-satisfying: Added missing \ni to interactive spec. +;; 2017/01/10 dadams +;; Renamed bmkp-toggle-allow-multi-tabs-for-w3m to bmkp-toggle-w3m-allow-multiple-buffers. +;; bmkp-bmenu-toggle-menu: Added bmkp-toggle-eww-allow-multiple-buffers. +;; 2017/01/08 dadams +;; Use the term "entry", not "property" everywhere, for bookmark entries (fields). +;; 2017/01/07 dadams +;; bmkp-bmenu-copy-marked-to-bookmark-file: Use bookmark-file-coding-system (Emacs bug #25365). +;; 2017/01/02 dadams +;; bmkp-bmenu-mouse-3-menu: Added menu item Store Org Link. +;; 2016/12/31 dadams +;; Added: bmkp-bmenu-mark-non-invokable-bookmarks, bmkp-bmenu-show-only-non-invokable-bookmarks. +;; Bound them to nM and nS. Added them to menus bmkp-bmenu-(mark|show)-types-menu. +;; bookmark-bmenu-mode: Include non-invokable bookmarks in doc string. +;; bmkp-bmenu-propertize-item: Handle non-invokable bookmarks. +;; 2016/11/23 dadams +;; bookmark-bmenu-mode: Doc string cleanup. +;; bookmark-bmenu-list, bmkp-bmenu-copy-marked-to-bookmark-file: +;; Raise an error if we have a directory, not a file. +;; bmkp-bmenu-create-bookmark-file-from-marked: Ensure that FILE is not a directory. +;; 2016/11/18 dadams +;; Support Emacs 24.[45] too. +;; 2016/11/15 dadams +;; bmkp-*eww-*: Ensure that EWW code is only for Emacs 25+. +;; 2016/11/14 dadams +;; Added: bmkp-bmenu-mark-eww-bookmarks, bmkp-bmenu-show-only-eww-bookmarks. +;; bookmark-bmenu-mode: Added EWW to doc. +;; Bound bmkp-bmenu-mark-eww-bookmarks to WEM, bmkp-bmenu-show-only-eww-bookmarks to WES. +;; Change bmkp-bmenu-mark-w3m-bookmarks to W3M, bmkp-bmenu-show-only-w3m-bookmarks binding to W3S. +;; bmkp-bmenu-mark-types-menu, bmkp-bmenu-show-types-menu: Support EWW. +;; 2016/06/24 dadams +;; bookmark-bmenu-execute-deletions: Delete bookmark on the current line if none flagged/marked. +;; 2016/06/23 dadams +;; bmkp-bmenu-(add|remove)-tags-(to|from)-marked, bmkp-bmenu-paste-(add|replace)-tags-for-marked: +;; Call bmkp-maybe-save-bookmarks (after the iteration). Thx to Alan Wehmann. +;; 2016/06/21 dadams +;; bmkp-bmenu-add-tags-to-marked, bmkp-bmenu-remove-tags-from-marked, +;; bmkp-bmenu-paste-(add|replace)-tags-to-marked: +;; Put bookmark-save-flag let-binding around iteration only, so modification is recorded etc. +;; 2016/06/11 dadams +;; bmkp-bmenu-list-1, bookmark-bmenu-hide-filenames: +;; Use string-width, not length. Thx to Toshikazu Nakamura. +;; 2015/11/07 dadams +;; bmkp-bmenu-copy-marked-to-bookmark-file: Added missing zerop test for No-changes case. +;; bmkp-bmenu-create-bookmark-file-from-marked: +;; Added missing MOVEP arg in call to bmkp-bmenu-copy-marked-to-bookmark-file. +;; 2015/11/02 dadams +;; bmkp-bmenu-copy-marked-to-bookmark-file: +;; If modified, prompt to save bookmark file copied from, before copying. +;; For copy (not move): reload the original bookmark file, then refresh display from it. +;; 2015/10/31 dadams +;; bmkp-bmenu-move-marked-to-bookmark-file: +;; Just call bmkp-bmenu-copy-marked-to-bookmark-file. It now deletes moved and refreshes list. +;; bmkp-bmenu-copy-marked-to-bookmark-file: +;; Added arg MOVEP. If move, delete before refresh list (deletes bmks returned in IMPORTED). +;; 2015/06/26 dadams +;; Added: bmkp-bmenu-mark-function-bookmarks, bmkp-bmenu-show-only-function-bookmarks. +;; Bound the to Q M and Q S. Added to bmkp-bmenu-show-types-menu. +;; bookmark-bmenu-mode: Updated the doc string for them. +;; bmkp-bmenu-show-only(-orphaned-local)-file-bookmarks: Made ARG optional. +;; 2015/05/15 dadams +;; Fixed typo: bmkp-bmenu-show-only-lighted -> bmkp-bmenu-show-only-lighted-bookmarks everywhere. +;; 2015/04/15 dadams +;; bmkp-bmenu-describe-this-bookmark: save-selected-frame -> save-selected-window. +;; 2015/03/20 dadams +;; Added: bmkp-bmenu-show-this-annotation+move-down, bmkp-bmenu-show-this-annotation+move-up, +;; bmkp-bmenu-kill-annotation, bmkp-remap. +;; Bind bmkp-bmenu-show-this-annotation+move-(down|up) to M-down, M-up. +;; bmkp-bmenu-describe-this+move-(down|up): Move first, then describe, not reverse. +;; bmkp-bmenu-describe-this-bookmark: Wrap with save-selected-frame. +;; 2015/02/22 dadams +;; Moved to bookmark+-1.el from here: +;; bmkp-reset-bmkp-store-org-link-checking-p, bmkp-store-org-link-checking-p. +;; Advice of org-store-link (not needed for bmkp-bmenu-store-org-link). +;; Soft-require org.el when compile, for org-add-link-type. +;; bmkp-bmenu-store-org-link: +;; Removed bmkp-store-org-link-checking-p (needed only for bmkp-store-org-link). +;; Link type changed from bookmark-other-window to bookmark-other-win. +;; Fix for lost annotation etc. edit the first time after showing display list: +;; bookmark-bmenu-list, bmkp-bmenu-define-full-snapshot-command: +;; Bind bookmark-alist to result of bmkp-refresh-latest-bookmark-list - do not just bind it to +;; bmkp-latest-bookmark-alist if available. (NOT SURE THIS IS RIGHT.) +;; bmkp-bmenu-list-1: +;; Removed update of bmkp-latest-bookmark-alist when not filteredp. (NOT SURE THIS IS RIGHT.) +;; bmkp-bmenu-menubar-menu: +;; Toggle menu: +;; Moved Toggle menu higher. +;; Moved bmkp-toggle-save-desktop-before-switching with other autosaving menu items. +;; Added bmkp-toggle-auto-light-when-jump-menu. +;; Moved temporary bookmark stuff lower, after display-list stuff. +;; bmkp-toggle-saving-menu-list-state: Corrected help text - affects also being able to save. +;; Moved bmkp-list-defuns-in-commands-file with other help stuff. +;; 2015/02/21 dadams +;; Added: bmkp-bmenu-store-org-link, bmkp-reset-bmkp-store-org-link-checking-p, +;; bmkp-store-org-link-checking-p. +;; Add bmkp-bmenu-store-org-link to org-store-link-functions. +;; Advise org-store-link with bmkp-reset-bmkp-store-org-link-checking-p. +;; Added bookmark(-other-window) link types via org-add-link-type. +;; 2015/02/08 dadams +;; Added: bmkp-bmenu-show-only-untagged-bookmarks. Added it to bmkp-bmenu-show-types-menu. +;; Renamed: bmkp-bmenu-*icicle-* to bmkp-bmenu-icicles-*, +;; bmkp-bmenu-show-only-*- to bmkp-bmenu-show-only-*-bookmarks. +;; Use new macro bmkp-define-show-only-command for the simple bmkp-bmenu-show-only-* commands. +;; 2014/12/18 dadams +;; bmkp-bmenu-show-only-specific-file: Restore vars if error. +;; 2014/12/04 dadams +;; *-dired-marked, *-move-marked-to-bookmark-file, *-copy-marked-to-bookmark-file, +;; *-create-bookmark-file-from-marked, *-set-bookmark-file-bookmark-from-marked, +;; *-(i)search-marked-bookmarks(-regexp), *-query-replace-marked-bookmarks-regexp, +;; *-set-tag-value-for-marked, *-add-tags-to-marked, *-remove-tags-from-marked, +;; *-paste-(add|replace)-tags-to-marked, *-relocate-marked, *-edit-marked, *-describe-marked: +;; Added arg INCLUDE-OMITTED-P. +;; 2014/11/09 dadams +;; bookmark-bmenu-show-annotation: Updated doc string to reflect updated bookmark-show-annotation. +;; 2014/08/22 dadams +;; bmkp-looking-at-p: Do not defalias to Emacs looking-at-p because that is a defsubst. +;; 2014/07/20 dadams +;; Protect key bindings for bmkp-bmenu-highlight-menu by boundp. +;; 2014/07/12 dadams +;; Added: bmkp-bmenu-relocate-marked. Bound to M-R. Added it to bmkp-bmenu-menubar-menu. +;; 2014/07/11 dadams +;; bmkp-bmenu-highlight-menu: Added item Toggle Autofile Highlighting in Dired. +;; bmkp-bmenu-toggle-menu: Added item Autofile Highlighting in Dired. +;; 2014/07/06 dadams +;; Toggle submenu: added lots, improved. +;; 2014/07/05 dadams +;; Added: bmkp-bmenu-create-bookmark-file-from-marked (bound to Y > 0), +;; bmkp-bmenu-set-bookmark-file-bookmark-from-marked, bmkp-bmenu-bookmark-file-menu. +;; Moved bookmark-file stuff to Bookmark File submenu. +;; bookmark-bmenu-mode: Updated doc string. +;; bmkp-bmenu-dired-marked: Use bmkp-bmenu-marked-or-this-or-all, not bmkp-marked-bookmarks-only. +;; bmkp-bmenu-marked-or-this-or-all: Added optional arg INCLUDE-OMITTED-P - else removed omitted. +;; 2014/07/04 dadams +;; Added to Bookmark+ menu: bmkp-bmenu-(copy|move)-marked-to-bookmark-file. +;; 2014/07/03 dadams +;; Added: bmkp-bmenu-copy-marked-to-bookmark-file, bmkp-bmenu-move-marked-to-bookmark-file. +;; Bound to Y > + and Y > -. +;; bookmark-bmenu-mode: Mention bmkp-bmenu-(copy|move)-marked-to-bookmark-file in doc string. +;; bookmark-bmenu-execute-deletions, bmkp-bmenu-delete-marked:: Added optional arg NO-CONFIRM-P. +;; bmkp-bmenu-define(-full-snapshot|jump)-command: Changed to C-c C-c, C-c C-S-c, C-c C-j. +;; bmkp-bmenu-show-all: Mention C-u g in doc string. +;; 2014/06/30 dadams +;; bmkp-bmenu-mouse-3-menu: +;; Bind bmkp-bmenu-flag-for-deletion, not bookmark-bmenu-delete. See Emacs bug #17888. +;; 2014/06/26 dadams +;; bmkp-bmenu-show-only-omitted: +;; Use bmkp-bmenu-omit/unomit-marked, not bmkp-bmenu-unomit-marked, in doc string. +;; bmkp-bmenu-remove-tags-from-marked: +;; Typo in interactive spec: allp -> current-prefix-arg. Thx to Alan Wehmann. +;; 2014/06/21 dadams +;; Added: bmkp-no-jump, bmkp-bmenu-mark-bookmark-list-bookmarks, +;; bmkp-bmenu-mark-icicle-search-hits-bookmarks, bmkp-bmenu-show-only-bookmark-lists, +;; bmkp-bmenu-show-only-icicle-search-hits. +;; bookmark-bmenu-list, bookmark-bmenu-mode: Updated doc string, for additions. +;; bmkp-bmenu-mode-status-help: Updated for no-jump (used for Icicles search hits bookmarks). +;; bmkp-bmenu-propertize-item: Handle Icicles search hits bookmarks. +;; Bind *-bmenu-mark-icicle-search-hits-bookmarks, *-bmenu-show-only-icicle-search-hits: i M, i S. +;; Bind bmkp-bmenu-mark-bookmark-list-bookmarks, bmkp-bmenu-show-only-bookmark-lists: Z M, Z S. +;; bmkp-bmenu-mark-types-menu: +;; Added bmkp-bmenu-mark-icicle-search-hits-bookmarks, bmkp-bmenu-mark-bookmark-list-bookmarks. +;; bmkp-bmenu-show-types-menu: +;; Added bmkp-bmenu-show-only-icicle-search-hits, bmkp-bmenu-show-only-bookmark-lists. +;; 2014/06/20 dadams +;; bmkp-define-tags-sort-command: Load bookmark+-mac.el(c) in interactive spec. +;; 2014/05/27 dadams +;; bmkp-bmenu-mode-status-help, bmkp-bmenu-describe-marked: +;; Use bmkp-with-help-window, not with-output-to-temp-buffer (Emacs 24.4+ silliness). +;; 2014/04/02 dadams +;; bmkp-bmenu-copy-tags, bmkp-bmenu-paste-replace-tags(for-marked): +;; Added Note to doc string about pasting an empty list of tags. +;; bmkp-bmenu-tags-menu: Added item Copy Tags from This Bookmark for bmkp-bmenu-copy-tags. +;; bmkp-bmenu-mouse-3-menu: Added :active bmkp-copied-tags for bmkp-bmenu-paste-add-tags. +;; 2014/04/01 dadams +;; Added: bmkp-bmenu-list-tags-of-marked. +;; Bind it to T > l in bookmark-bmenu-mode-map. +;; Add it to bmkp-bmenu-tags-menu. +;; bookmark-bmenu-mode: List bmkp-bmenu-list-tags-of-marked in doc string. +;; 2014/03/29 dadams +;; Added variable bmkp-bmenu-define-command-history. +;; bmkp-bmenu-define(-jump-marked|-full-snapshot)-command: +;; Removed quote before bmkp-bmenu-define-command-history. +;; Toggle submenu: Use bmkp-menu-bar-make-toggle. +;; 2014/03/28 dadams +;; bmkp-bmenu-describe-marked: Apply bmkp-sort-omit, to show bookmarks in the current sort order. +;; 2014/03/23 dadams +;; Added: bmkp-bmenu-delete-menu, bmkp-bmenu-mark-types-menu, bmkp-bmenu-search-menu, +;; bmkp-bmenu-show-types-menu, bmkp-bmenu-toggle-menu. Move menu items there from top. +;; bookmark-bmenu-mode-map: +;; Bind jump commands to j prefix and J prefix (like C-x 4 j and C-x j). +;; Bind bookmark-bmenu-locate to C-S-l, since w is used as a prefix key now. +;; bookmark-bmenu-mode: New jump bindings. Added bmkp-bmenu-copy-tags. +;; 2014/03/21 dadams +;; bookmark-bmenu-mode: List also global bindings for tag commands. +;; 2014/03/10 dadams +;; bmkp-maybe-unpropertize-bookmark-names: Remove prop face & Icicles props, in any case. +;; bmkp-bmenu-define(-jump-marked|-full-snapshot)-command, bmkp-define-tags-sort-command: +;; Bind print-circle to bmkp-propertize-bookmark-names-flag, not t, to avoid string reuse. +;; 2013/12/13 dadams +;; bmkp-bmenu-mode-line: +;; To avoid Emacs crashes from bug #12867: Do not define it for Emacs 22-23, and wrap +;; condition-case around the whole function body. +;; 2013/12/11 dadams +;; bmkp-bmenu-mode-line: Protect %360l (line) hack with condition-case. +;; 2013/10/07 dadams +;; bmkp-bmenu-edit-marked: If no marked bmks, mark the current line bmk, to start with. +;; Use correct buffer when go to point-min. +;; 2013/08/09 dadams +;; Added: bmkp-looking-at-p. Use it instead of looking-at, everywhere. +;; 2013/07/02 dadams +;; Added to menu-bar Edit menu: bmkp-set-snippet-bookmark, bmkp-snippet-to-kill-ring. +;; 2013/06/30 dadams +;; Added: bmkp-snippet, bmkp-bmenu-show-only-snippets, bmkp-bmenu-mark-snippet-bookmarks. +;; bookmark-bmenu-list: Added snippet info to doc string. +;; bmkp-bmenu-mode-status-help: Cover snippets too. +;; Bind bmkp-bmenu-(mark-snippet-bookmarks|show-only-snippets) to w M, w S. Add to menus. +;; 2013/06/29 dadams +;; bmkp-bmenu-regexp-mark, bmkp-bmenu-search-marked-bookmarks-regexp, +;; bmkp-bmenu-(un)mark-bookmarks-tagged-regexp: +;; Use bmkp-read-regexp in interactive spec. +;; bmkp-bmenu-mode-status-help: Ensure that we have a supported image before calling insert-image. +;; 2013/06/09 dadams +;; bmkp-bmenu-mode-line-string: Added missing let-binding for REGEXP. +;; Added vacuous defvars to suppress free-var warnings. +;; 2013/05/28 dadams +;; Renamed: bmkp-bmenu-edit-bookmark-name-and-file to bmkp-bmenu-edit-bookmark-name-and-location. +;; 2013/05/28 dadams +;; bmkp-bmenu-list-1: Do not call put-image if create-image returns nil. +;; 2013/05/15 dadams +;; Moved here from bookmark+-1.el: bmkp-string-match-p. +;; Use bmkp-string-match-p instead of string-match wherever appropriate. +;; 2013/04/10 dadams +;; bmkp-bmenu-make-sequence-from-marked: Redefine using bmkp-set-sequence-bookmark (new). +;; 2013/01/07 dadams +;; bookmark-bmenu-mode: +;; Added: bmkp-bmenu-set-tag-value-for-marked, bmkp-bmenu-paste-(add|replace)-tags-for-marked. +;; Mention C-u = all, for marked. +;; 2013/01/04 dadams +;; bmkp-bmenu-show-only-tagged: Corrected filter function. +;; 2012/11/14 dadams +;; bmkp-bmenu-mode-line: Added mode-line-buffer-identification. +;; 2012/11/12 dadams +;; Added: bmkp-bmenu-marked-or-this-or-all. +;; bmkp-bmenu-isearch-marked-bookmarks(-regexp), bmkp-bmenu-search-marked-bookmarks-regexp, +;; bmkp-bmenu-query-replace-marked-bookmarks-regexp, bmkp-bmenu-set-tag-value-for-marked, +;; bmkp-bmenu-add-tags-to-marked, bmkp-bmenu-remove-tags-from-marked, +;; bmkp-bmenu-paste-(add|replace)-tags-(to|for)-marked, bmkp-bmenu-edit-marked, +;; bmkp-bmenu-describe-marked: +;; Make it work for current bookmark if none marked. +;; bmkp-bmenu-isearch-marked-bookmarks(-regexp), bmkp-bmenu-search-marked-bookmarks-regexp, +;; bmkp-bmenu-set-tag-value-for-marked, bmkp-bmenu-add-tags-to-marked, +;; bmkp-bmenu-remove-tags-from-marked, bmkp-bmenu-paste-(add|replace)-tags-(to|for)-marked, +;; bmkp-bmenu-edit-marked: +;; Make it work for all bookmarks if use prefix arg. +;; Protect all calls to bmkp-bmenu-mode-line with fboundp, for Emacs 20. +;; 2012/11/11 dadams +;; Added: bmkp-bmenu-mode-line, bmkp-bmenu-mode-line-string. +;; Removed: bmkp-bmenu-nb-marked-in-mode-name (replaced by bmkp-bmenu-mode-line - shows more). +;; Removed faces bmkp-mode-line-marked, bmkp-mode-line-flagged. +;; bookmark-bmenu-(delete|(un)mark), bmkp-bmenu-list-1: Call bmkp-bmenu-mode-line. +;; bookmark-bmenu-execute-deletions: Inhibit saving until all are deleted, then save. +;; bmkp-bmenu-mode-status-help: Show > and D using their faces, bmkp->-mark, bmkp-D-mark. +;; Use "" if bmkp-current-sort-order (new version) returns nil. +;; 2012/10/09 dadams +;; Made all autoload cookies explicitly load bookmark+.el(c). Should help ELPA (e.g. MELPA). +;; 2012/09/29 dadams +;; Added: bmkp-maybe-unpropertize-string. +;; bmkp-maybe-unpropertize-bookmark-names: Added optional arg COPY. +;; bmkp-bmenu-define(-jump-marked|-full-snapshot|-tags-sort)-command: +;; Bind print-circle, version-control, require-final-newline. +;; Use find-file-noselect & write-file, not write-region. +;; bmkp-bmenu-define-jump-marked-command: Use bmkp-maybe-unpropertize-bookmark-names on bookmarks. +;; bmkp-bmenu-define-full-snapshot-command: +;; Copy shared bookmark lists and single strings, to avoid circular refs. +;; Expand file names and use convert-standard-filename, for bookmark file names. +;; 2012/09/28 dadams +;; Added: bmkp-bmenu-jump-to-marked. +;; Renamed: bmkp-bmenu-w32-open-select to bmkp-bmenu-w32-jump-to-marked. +;; Replace bookmark-bmenu-select with bmkp-bmenu-jump-to-marked, everywhere. +;; bmkp-bmenu-w32-open-with-mouse: +;; Rewrote to directly call bookmark-handle-bookmark, jump-fn, and show annotations. +;; 2012/09/03 dadams +;; bookmark-bmenu-toggle-filenames: Added missing nil FORCE arg. +;; bmkp-bmenu-list-1: Call bookmark-bmenu-toggle-filenames with NO-MSGP arg. +;; Removed: bmkp-bmenu-filter-prompt. bmkp-bmenu-read-filter-input: hard-code the prompt. +;; 2012/06/26 dadams +;; Moved here from bookmark+-mac.el: bmkp-assoc-delete-all, bmkp-replace-regexp-in-string. +;; Wrapped require of bookmark+-mac.el in eval-when-compile. +;; 2012/06/21 dadams +;; Added: bmkp-bmenu-nb-marked-in-mode-name. Added to bookmark-bmenu-mode-hook. +;; Try to load-library bookmark+-mac. Require it only if cannot load-library. +;; 2012/06/15 dadams +;; bookmark-bmenu-mode, bmkp-bmenu-mode-status-help: Improved doc string. +;; bmkp-bmenu-show-or-edit-annotation: Corrected doc string: bookmark, not buffer. +;; 2012/06/14 dadams +;; Added face bmkp-no-local. +;; Redefined defaults for faces bmkp-non-file and bmkp-variable-list. +;; bmkp-bmenu-mode-status-help: Added legend for no such local file. +;; bmkp-bmenu-propertize-item: Distinguish no such local file from no such existing buffer. +;; 2012/06/13 dadams +;; bookmark-bmenu-bookmark: forward-char bmkp-bmenu-marks-width, not 1+ that. +;; bmkp-bmenu-propertize-item: Allow a file bookmark to get buffer prop if file not yet saved. +;; Do not require buffer-name attribute for bmkp-non-file face. +;; 2012/06/11 dadams +;; bmkp-bmenu-propertize-item: Use bmkp-non-file-filename also if filename is missing from bmk. +;; 2012/05/05 dadams +;; bookmark-bmenu-(un)mark(-all), bmkp-bmenu-regexp-mark, bmkp-bmenu-toggle-marks, +;; bmkp-bmenu-mark-bookmarks-satisfying, bmkp-bmenu-toggle-marked-temporary/savable, +;; bmkp-bmenu-(un)mark-bookmarks-tagged-regexp: +;; Added optional arg MSG-P. +;; bookmark-bmenu-(un)mark(-all), bookmark-bmenu-execute-deletions, bmkp-bmenu-regexp-mark, +;; bmkp-bmenu-toggle-show-only-(un)marked, bmkp-bmenu-mark-bookmarks-satisfying, +;; bmkp-bmenu-toggle-marks, bmkp-bmenu-toggle-marked-temporary/savable, +;; bmkp-bmenu-toggle-temporary, bmkp-bmenu-make-sequence-from-marked, +;; bmkp-bmenu-(un)omit(-marked), bmkp-bmenu-(un)mark-bookmarks-tagged-regexp, +;; bmkp-bmenu-mark/unmark-bookmarks-tagged-*, bmkp-bmenu-change-sort-order, +;; bmkp-reverse(-multi)-sort-order: +;; Pass NO-MSG-P to *-refresh/rebuild-menu-list, *-surreptitiously-rebuild-list, *-store. +;; bmkp-bmenu-mark/unmark-bookmarks-tagged-(all/none|some/not-all): +;; Swapped last two args, so consistent order. +;; bmkp-bmenu-(un)mark-bookmarks-tagged-*: Updated arg order in calls to b-b-m/u-b-t-(a/n|s/n-a). +;; bmkp-bmenu-(un)mark-bookmarks-tagged-regexp, bmkp-bmenu-mark/unmark-bookmarks-tagged-*: +;; Added status message. +;; 2012/05/01 dadams +;; Added redefinition of bookmark-bmenu-delete-backwards (they broke its movement). +;; Added aliases: bmkp-bmenu-flag-for-deletion(-backwards). Bind to d, k, C-d (same as aliases). +;; bmkp-bmenu-(add|remove)-tags, bmkp-bmenu-(add|remove)-tags-(to|from)-marked: +;; Automatically re-sort if # tagged bmks changed and sort order is tagged first/last (s t). +;; Added: bmkp-bmenu-sort-tagged-before-untagged. +;; Bind bmkp-bmenu-sort-tagged-before-untagged to s t. +;; Bind bmkp-bmenu-sort-by-last-bookmark-access to s d, not s t. +;; Bind bmkp-bmenu-sort-by-last-local-file-access to s f d, not s f t. +;; Bind bmkp-bmenu-sort-by-local-file-type to s f k, not s f d. +;; 2012/04/28 dadams +;; bookmark-bmenu-(un)mark(-all), bmkp-bmenu-regexp-mark, bmkp-bmenu-mark-bookmarks-satisfying, +;; bmkp-bmenu-toggle-marks, bmkp-bmenu-(un)mark-bookmarks-tagged-regexp, +;; bmkp-bmenu-mark/unmark-bookmarks-tagged-(all/none|some/not-all): +;; Added optional arg NO-RE-SORT-P. +;; Automatically re-sort if marks changed and if sort order is marked first/last (s >). +;; Changed all non-interactive calls of bookmark-bmenu-(un)mark to pass non-nil NO-RE-SORT-P. +;; bmkp-bmenu-toggle-marks: Call bookmark-bmenu-ensure-position at start. +;; 2012/04/27 dadams +;; bmkp-bmenu-edit-marked: Use bmkp-with-output-to-plain-temp-buffer. +;; 2012/04/13 dadams +;; Added: bmkp-bmenu-sort-(flagged|modified)-before-un(flagged|modified), bmkp-flagged-bookmarks. +;; Bound bmkp-bmenu-sort-(flagged|modified)-before-un(flagged|modified) to s D, s *. +;; bookmark-bmenu-(un)mark: Delete bookmark from bmkp-flagged-bookmarks. +;; bookmark-bmenu-mark: Use (equivalent of) eq version of add-to-list. +;; bookmark-bmenu-delete: Add bookmark to bmkp-flagged-bookmarks. +;; bmkp-bmenu-list-1: Always reset bmkp-(flagged|modified)-bookmarks. +;; Flag bookmarks if bmkp-flagged-bookmark-p. +;; bmkp-bmenu-refresh-menu-list: C-u resets bmkp-flagged-bookmarks too. +;; 2012/04/10 dadams +;; bmkp-bmenu-load-marked-bookmark-file-bookmarks: +;; Use bmkp-refresh-menu-list, not bmkp-refresh/rebuild-menu-list. +;; bmkp-bmenu-(add|remove)-tags-(to|from)-marked, bmkp-bmenu-paste-(add|replace)-tags-to-marked: +;; Corrected bookmark-save to bookmark-save-flag in bindings to nil. +;; Use bmkp-count-multi-mods-as-one-flag for the binding. +;; Call bmkp-refresh-menu-list. +;; 2012/04/09 dadams +;; bmkp-bmenu-set-tag-value, bmkp-bmenu-remove-tags, bmkp-bmenu-paste-(add|replace)-tags: +;; Added nil NO-UPDATE-P arg in calls to bmkp-set-tag-value, bmkp-remove-tags, +;; bmkp-paste-(add|replace)-tags. +;; bmkp-bmenu-add-tags-to-marked, bmkp-bmenu-remove-tags-from-marked, +;; bmkp-bmenu-paste-(add|replace)-tags-to-marked: +;; Bind bookmark-save to nil around iteration, to inhibit saving until finished. +;; New arg order for calls to bmkp-(add|remove)-tags. +;; Pass non-nil NO-UPDATE-P arg to bmkp-paste-(add|replace)-tags. +;; 2012/04/03 dadams +;; Moved here from bookmark+-1.el: bmkp-face-prop. +;; 2012/03/19 dadams +;; Added: bmkp-*-mark. +;; bmkp-bmenu-list-1, bmkp-bmenu-mode-status-help: Use bmkp-*-mark for *. +;; 2012/03/18 dadams +;; bookmark-bmenu-delete: Remove bookmark from bmkp-modified-bookmarks also. +;; bmkp-bmenu-list-1: RESET-P resets bmkp-modified-bookmarks also. Insert modified marks (*). +;; bmkp-bmenu-refresh-menu-list: +;; When revert from file: Reset *-marked-bookmarks, *-modified-bookmarks, *-omitted-bookmarks. +;; Bind bmkp-bmenu-filter-function to nil for bmkp-refresh-menu-list. +;; bmkp-bmenu-toggle-show-only-(un)marked: +;; Save display, so bmkp-bmenu-before-hide-marked-alist is up-to-date. +;; bmkp-bmenu-mode-status-help: Added legend for markings. +;; bmkp-bmenu-edit-marked: Use (shallow) copies of bookmarks, not originals. +;; Added bmkp-save-menu-list-state to Bookmark+ menu. +;; 2012/03/13 dadams +;; bmkp-bmenu-read-filter-input: +;; If C-g then restore previous display. +;; Use only one catch and test while condition. +;; Do not try to pop an empty list. +;; bmkp-bmenu-filter-((bookmark|file)-name|annotation|tags)-incrementally: +;; Use run-with-idle-timer, not run-with-timer +;; 2012/03/11 dadams +;; Added Revert to Saved (bmkp-revert-bookmark-file) to menu. +;; 2012/03/07 dadams +;; bmkp-bmenu-load-marked-bookmark-file-bookmarks: Use bmkp-sorted-alist to load in display order. +;; 2012/03/06 dadams +;; bookmark-bmenu-mode: Reorg. +;; bmkp-bmenu-refresh-menu-list: +;; Call bmkp-refresh-menu-list also when revert file. Use yes-or-no-p, not y-or-n-p. +;; 2012/03/05 dadams +;; bmkp-bmenu-mode-status-help: Added Autosave bookmarks and Autosave list display to info at top. +;; 2012/03/04 dadams +;; Added: bmkp-bmenu-load-marked-bookmark-file-bookmarks. +;; Bind bmkp-toggle-saving-menu-list-state to C-M-~, not M-l. +;; Bind bmkp-bmenu-load-marked-bookmark-file-bookmarks to M-l. Add it to menu. +;; 2012/03/02 dadams +;; bookmark-bmenu-list: Reset marked and omitted lists to () if a name is not a current bmk. +;; 2012/02/28 dadams +;; Added face bmkp-file-handler. +;; bmkp-bmenu-mode-status-help: Added bmkp-file-handler to face legend. +;; bmkp-bmenu-propertize-item: Propertize file-handler bookmarks, with bmkp-file-handler. +;; 2011/12/31 dadams +;; Define macro with-buffer-modified-unmodified for Emacs 23.1, in addition to Emacs < 23. +;; 2011/12/30 dadams +;; Added aliases: bmkp-bookmark-(data|name)-from-record. +;; Added: bmkp-bmenu-show-or-edit-annotation, bmkp-bmenu-edit-bookmark-record, +;; bmkp-bmenu-edit-marked. +;; Renamed bmkp-bmenu-edit-bookmark to bmkp-bmenu-edit-bookmark-name-and-file. +;; bookmark-bmenu-mark: Propertize bookmark name with bmkp-full-record before adding to list. +;; bookmark-bmenu-list: +;; Added optional arg MSGP. Show status messages. +;; Propertize bookmark names if not already propertized, in marked and omitted lists. +;; bookmark-bmenu-mode: Updated doc string. +;; bmkp-bmenu-make-sequence-from-marked: +;; Use bmkp-get-bookmark-in-alist, not bookmark-get-bookmark. +;; Bind bmkp-bmenu-show-or-edit-annotation (not *-show-annotation) to a. +;; Bind bmkp-bmenu-edit-bookmark-name-and-file to r now, not E. +;; Bind bmkp-bmenu-edit-marked to E and T > e. +;; Bind bmkp-bmenu-edit-bookmark-record to e. +;; bmkp-bmenu-quit: Show progress messages. +;; bmkp-bmenu-tags-menu: Added bmkp-bmenu-edit-marked. +;; bmkp-bmenu-mouse-3-menu: +;; Added: bmkp-bmenu-edit-tags. +;; Replaced *-rename and *-relocate with bmkp-bmenu-edit-bookmark-name-and-file. +;; 2011/12/24 dadams +;; Added: bookmark-bmenu-toggle-filenames, with optional arg NO-MSG-P. +;; bookmark-bmenu-surreptitiously-rebuild-list, bookmark-bmenu-(show|hide)-filenames: +;; Added progress messages and optional arg NO-MSG-P. +;; bookmark-bmenu-(show|hide)-filenames, bookmark-bmenu-toggle-filenames: +;; Correct FORCE behavior and doc strings. +;; bmkp-bmenu-refresh-menu-list: Pass (not) MSG-P to bmkp-refresh-menu-list. +;; 2011/12/21 dadams +;; Added: bmkp-bmenu-mark-orphaned-local-file-bookmarks, +;; bmkp-bmenu-show-only-orphaned-local-files, bmkp-bmenu-mark-variable-list-bookmarks. +;; bmkp-bmenu-refresh-menu-list: Added optional args ARG and MSGP, so you can revert from file. +;; bookmark-bmenu-mode: Updated and reordered doc string. +;; Bind O M, O S to orphaned commands, not omit commands. Changed omit bindings to use -, not O. +;; Bind bmkp-bmenu-mark-variable-list-bookmarks to V M. +;; bmkp-bmenu-show-menu: Reordered. Added: *-w3m-urls, *-variable-lists, *-orphaned-local-files. +;; bmkp-bmenu-mark-menu: Reordered. Added: *-w3m-*, *-variable-list-*, *-orphaned-local-file-*. +;; 2011/12/19 dadams +;; Added: with-buffer-modified-unmodified. +;; bookmark-bmenu-((un)mark|delete), bookmark-bmenu-(show|hide)-filenames: +;; Use with-buffer-modified-unmodified. +;; bookmark-bmenu-show-filenames, bmkp-bmenu-mouse-3-menu: Use line-(beginning|end)-position. +;; 2011/12/15 dadams +;; bmkp-bmenu-propertize-item: Use bmkp-local-directory face also for Dired (e.g. with wildcards). +;; bmkp-bmenu-mode-status-help: Clarify legend for remote and local dirs/Dired. +;; 2011/12/08 dadams +;; bmkp-bmenu-mouse-3-menu: Use easymenu to build the menu. Conditionalize some items. +;; Bind down-mouse-3, not mouse-3, to bmkp-bmenu-mouse-3-menu. (bind mouse-3 to ignore). +;; Added eval-when-compile for easymenu.el. +;; 2011/12/05 dadams +;; bmkp-bmenu-menubar-menu: Reordered items regarding bookmark files. +;; bmkp-bmenu-mode-status-help: Correct intro text, reorder, use marker for position TOP. +;; bookmark-bmenu-mode: Changed intro text slightly. +;; 2011/12/03 dadams +;; bmkp-bmenu-list-1: Print current bookmark file at top of display. +;; Increased bmkp-bmenu-header-lines to 5. +;; bookmark-bmenu-mode: Updated doc string for binding changes and new option. +;; bmkp-bmenu-regexp-mark: Mention right-padding of bookmark names in doc string. +;; bmkp-bmenu-mode-status-help: Reorder Current Status items, to put bookmark file first. +;; Bind L to bmkp-switch-bookmark-file-create, not bmkp-switch-bookmark-file. +;; 2011/11/19 dadams +;; bmkp-bmenu-image-bookmark-icon-file: Default to an existing Emacs image file, not nil. +;; 2011/11/18 dadams +;; Added: bmkp-bmenu-mark-image-bookmarks, bmkp-bmenu-show-only-image-files, +;; bmkp-bmenu-image-bookmark-icon-file. +;; bmkp-bmenu-list-1: Show icon image for image-file bookmarks. +;; bookmark-bmenu-mode: Add to doc string: bmkp-image-jump, bmkp-bmenu-mark-image-bookmarks, +;; bmkp-bmenu-show-only-image-files. +;; bmkp-bmenu-mode-status-help: Added image icon to legend. +;; Bound keys: M-I M-M, M-I M-S to *-mark-image-bookmarks *-show-only-image-files. +;; Added to menus (Mark, Show): bmkp-bmenu-mark-image-bookmarks, bmkp-bmenu-show-only-image-files. +;; 2011/11/01 dadams +;; bookmark-bmenu-mode: Changed mode-name var for mode line: Bookmarks, not Bookmark Menu. +;; Updated doc string for autofile & temporary jump commands. +;; 2011/10/31 dadams +;; bookmark-bmenu-mode: Updated doc string with bmkp-toggle-autotemp-on-set. +;; bmkp-bmenu-menubar-menu: Added: bmkp-toggle-autotemp-on-set. +;; 2011/10/27 dadams +;; Added: bmkp-X-mark, bmkp-bmenu-toggle-marked-temporary/savable, bmkp-bmenu-toggle-temporary, +;; bmkp-bmenu-mark-autonamed-bookmarks, bmkp-bmenu-show-only-temporary, +;; bmkp-bmenu-mark-temporary-bookmarks. +;; bmkp-bmenu-list-1: Mark with X in place of a, if bookmark is temporary. +;; bookmark-bmenu-mode: Mode-line major-mode name indicates when in temporary bookmarking mode. +;; Updated doc string with temporary bookmark commands. +;; bmkp-t-mark: Changed default attributes. +;; Bind: M-L to bmkp-temporary-bookmarking-mode, M-X to bmkp-bmenu-toggle-marked-temporary/savable +;; X M to bmkp-bmenu-mark-temporary-bookmarks, X S to bmkp-bmenu-show-only-temporary, +;; C-M-X to bmkp-bmenu-toggle-temporary. +;; bmkp-bmenu-show-only-bookmark-files: Bind to Y S, not X S. +;; bmkp-bmenu-mark-bookmark-file-bookmarks: Bind to Y M, not X M. +;; 2011/07/01 dadams +;; bmkp-bmenu-change-sort-order, bmkp(-multi)-reverse-sort-order: Handle null CURRENT-BMK. +;; 2011/04/24 dadams +;; Added to Tags menu: Purge Autofiles with No Tags. +;; 2011/04/23 dadams +;; Bound bmkp-bmenu-set-tag-value-for-marked to T > v and added to bmkp-bmenu-tags-menu. +;; bmkp-bmenu-mouse-3-menu: Added bmkp-rename-tag. +;; 2011/04/22 dadams +;; Bound *-copy-tags to T c, T M-w, *-paste(-add|replace)-tags to T p, T C-y, T q. +;; 2011/04/21 dadams +;; Added: bmkp-bmenu-copy-tags, bmkp-bmenu-paste-add-tags(-to-marked), +;; bmkp-bmenu-paste-replace-tags(-for-marked). +;; Bound and added to menus: bmkp-bmenu-paste-add-tags-to-marked, +;; bmkp-bmenu-paste-replace-tags-for-marked. +;; Added to This Bookmark menu: bmkp-bmenu-copy-tags, bmkp-bmenu-paste(-add|replace)-tags. +;; 2011/04/19 dadams +;; Added: bmkp-bmenu-unmark-bookmarks-tagged-regexp. Bound it to T u %. Added it to menu. +;; 2011/04/16 dadams +;; Added: bmkp-edit-tags-send. Bound it to T e in bookmark-bmenu-mode-map. +;; bookmark-bmenu-mode: Updated help text for tags editing. +;; bmkp-maybe-unpropertize-bookmark-names: +;; Test emacs-major-version, not just (boundp 'print-circle). +;; 2011/04/15 dadams +;; Added: bmkp-bmenu-mark-autofile-bookmarks, bmkp-bmenu-show-only-autofiles. +;; And added them to menus. +;; bookmark-bmenu-mode-map: +;; Bind bmkp-bmenu-mark-autofile-bookmarks, bmkp-bmenu-show-only-autofiles to A M, A S. +;; Bind bookmark-bmenu-show-all-annotations to M-a, not A. +;; Bind bmkp-bmenu-search-marked-bookmarks-regexp to M-s a M-s, not M-a. +;; Bind *-mark-url-bookmarks, *-show-only-urls to M-u M-m, M-u M-s, not M-u M, M-u S. +;; bookmark-bmenu-mode: Updated help to reflect latest bindings. +;; 2011/04/13 dadams +;; bmkp-bmenu-tags-menu: Added: bmkp-(un)tag-a-file. +;; 2011/04/12 +;; Added: bmkp-propertize-bookmark-names-flag, bmkp-maybe-unpropertize-bookmark-names, +;; bmkp-bmenu-get-marked-files. +;; Renamed: bmkp-bmenu-omitted-list to bmkp-bmenu-omitted-bookmarks. +;; bmkp-bmenu-define-full-snapshot-command: +;; Bind print-circle to t around pp. Use bmkp-maybe-unpropertize-bookmark-names on lists. +;; bookmark-bmenu-(show|hide)-filenames, bmkp-bmenu-toggle-show-only-(un)marked, +;; bmkp-bmenu-(un)omit-marked: +;; Fit one-window frame only if selected window is *Bookmark List*. +;; bookmark-bmenu-bookmark: Added optional arg FULL. Non-nil means return full bookmark record. +;; bookmark-bmenu-unmark, bookmark-bmenu-delete, bmkp-bmenu-unomit-marked: +;; Use bmkp-delete-bookmark-name-from-list, not delete. +;; bookmark-bmenu-execute-deletions: Pass full bookmark, not name, to delete, and don't use assoc. +;; bookmark-bmenu-rename: Use bmkp-bmenu-goto-bookmark-named instead of just searching for name. +;; bmkp-bmenu-toggle-marks, bmkp-bmenu-unomit-marked, bmkp-bmenu-define-jump-marked-command, +;; bmkp-bmenu-mouse-3-menu: +;; Use bmkp-bookmark-name-member, not member. +;; bmkp-bmenu-make-sequence-from-marked: Do not invoke bookmark-bmenu-list when no displayed list. +;; bmkp-bmenu-define-command: Use bmkp-maybe-unpropertize-bookmark-names on *-omitted-bookmarks. +;; bmkp-bmenu-list-1: Use bmkp-sort-omit, not bmkp-sort-and-remove-dups. +;; Pass full bookmark to bmkp-bmenu-propertize-item. +;; bmkp-bmenu-propertize-item: +;; First arg is now a full bookmark, not a bookmark name. Get bookmark name from it. +;; Put prop bmkp-bookmark-name on buffer text with propertized bookmark-name string as value. +;; String has property bmkp-full-record with value the full bookmark record, with string as car. +;; Return propertized bookmark-name string. +;; bmkp-bmenu-isearch-marked-bookmarks(-regexp), bmkp-bmenu-dired-marked, +;; bmkp-bmenu-(search|query-replace)-marked-bookmarks-regexp: +;; Use bmkp-sort-omit, not bmkp-sort-and-remove-dups. +;; bmkp-bmenu-goto-bookmark-named: +;; If NAME has property bmkp-full-record then go to the bookmark it indicates. Otherwise, just +;; go to the first bookmark with the same name. +;; bookmark-bmenu-mode: Added bmkp-save-menu-list-state (now a command) to the mode help. +;; 2011/04/02 dadams +;; bookmark-bmenu-mode: Added to mode help: bmkp-file-this-dir-(all|some)-tags(-regexp)-jump., +;; Create/Set section, with bmkp-autofile-set. +;; 2011/04/01 dadams +;; bookmark-bmenu-mode: Added to mode help: bmkp-(dired|file)-this-dir-jump. +;; 2011/03/26 dadams +;; bookmark-bmenu-mode: Added new file-with-tags jump commands to the help. +;; 2011/03/05 dadams +;; bmkp-bmenu-edit-bookmark: Use bmkp-refresh-menu-list, not *-surreptitiously-rebuild-list. +;; 2011/02/11 dadams +;; Faces: Better defaults for dark background. +;; 2011/01/03 dadams +;; Removed autoload cookies from non def* sexps and from define-key. +;; Added missing autoload cookies for commands, in particular redefined std commands & defalias. +;; 2010/12/10 dadams +;; Added defalias for bookmark-name-from(-full)-record, to fix gratuitous Emacs name change. +;; 2010/09/24 dadams +;; Added: bmkp-bmenu-show-only-autonamed. Bound to # S. Added to bmkp-bmenu-show-menu. +;; bookmark-bmenu-mode: Updated doc string for autonamed jumps, show. +;; Renamed varlist to variable-list everywhere. +;; 2010/08/22 dadams +;; Added: bmkp-bmenu-filter-annotation-incrementally, bookmark-bmenu-relocate (Emacs 20, 21), +;; bmkp-bmenu-filter-alist-by-annotation-regexp. Bound, added to menus and help. +;; 2010/08/18 dadams +;; Removed eval-when-compile for bookmark+-(lit|1).el. +;; bmkp-bmenu-propertize-item: Inconsequential simplification. +;; 2010/08/17 dadams +;; bmkp-bmenu-edit-bookmark: Added optional arg INTERNALP (prefix arg), for editing record. +;; 2010/08/15 dadams +;; Moved to bookmark+-mac.el: +;; bmkp-define-sort-command, bmkp-replace-regexp-in-string, bmkp-assoc-delete-all. +;; Renamed: bmkp-barf-if-not-in-menu-list to bmkp-bmenu-barf-if-not-in-menu-list. +;; Require bookmark.el, bookmark+-mac.el. +;; Require when compile: bookmark+-1.el, bookmark+-lit.el (soft). +;; 2010/07/17 dadams +;; Added: bmkp-bmenu-mark-url-bookmarks, bmkp-bmenu-show-only-urls, bmkp-bmenu-sort-by-url. +;; Removed: bmkp-bmenu-sort-by-w3m-url. +;; Replaced face bmkp-w3m by bmkp-url. +;; bookmark-bmenu-mode: Added mark and show URL commands. +;; bookmark-bmenu-mode, *-status-help, *-sort-by-bookmark-type, *-define-sort-command: w3m -> url. +;; Bind bmkp-bmenu-sort-by-url, not bmkp-bmenu-sort-by-w3m-url. +;; Bind bmkp-bmenu-mark-url-bookmarks, bmkp-bmenu-show-only-urls. +;; Replace W3M by URL in menu items. +;; 2010/07/14 dadams +;; Created from bookmark+.el code. + +;;;(@* "CHANGE LOG FOR `bookmark+-doc.el'") +;; +;; 2020/07/04 dadams +;; Changed all references to `C-x p' to `C-x x'. + +;;;(@* "CHANGE LOG FOR `bookmark+-key.el'") +;; +;; 2021/09/19 dadams +;; Everywhere: Use bmkp-bmenu-buffer, not vanilla bookmark-bmenu-buffer. +;; 2021/02/12 dadams +;; Typo in eval-after-load for EWW: previous -> next. +;; 2020/07/04 dadams +;; Changed all `C-x p' to `C-x x'. +;; Replaced string *Bookmark List* with bookmark-bmenu-buffer (for Emacs 28). +;; 2020/06/20 dadams +;; Correctly added bmkp-compilation-target-set(-all) to compilation and grep maps. +;; 2020/01/27 dadams +;; Bind bookmark-jump-other-frame to 5 in bookmark-map. +;; 2020/01/25 dadams +;; bmkp-bookmarks-here-menu-command-entries: +;; Added bmkp-edit-bookmark-record-file/buffer, bmkp-set-lighting-for-this-buffer, +;; bmkp-unlight-this-buffer, bmkp-(un)light-(non-)autonamed-this-buffer +;; Use bmkp-light-this-buffer, not bmkp-light-bookmarks. +;; menu-bar-bookmark-map > bmkp-here-menu: Rename; use bmkp-exists-this-file/buffer-bookmarks-p. +;; 2020/01/24 dadams +;; Added: bmkp-annotate-map, bmkp-annotate-menu. +;; bmkp-bookmarks-here-menu-command-entries, bmkp-highlight-menu: +;; Added: bmkp-describe-bookmark-lighted-here. +;; bmkp-bookmarks-here-menu-command-entries: +;; Added: bmkp-light-bookmarks, bmkp-bookmarks-lighted-at-point, +;; bmkp-annotate-bookmark-this-file/buffer, bmkp-annotate-all-bookmarks-this-file/buffer. +;; Bind annotation commands to prefix C-x p a (bmkp-annotate-map). +;; Move Here submenu before Highlight submenu. +;; Typo in name when binding: bmkp-this-file/buffer-bmenu-list. +;; 2020/01/22 dadams +;; Bind bmkp-switch-to-bookmark-file-this-file/buffer to C-x p C-l, +;; bmkp-save-bookmarks-this-file/buffer to C-x p C-s. +;; Change bmkp-jump-to-list from C-x [pj] C-l to C-x [pj] C-j. +;; bmkp-bookmarks-here-menu-command-entries: +;; Added bmkp-(switch-to-bookmark-file|save-bookmarks)-this-file/buffer. +;; 2019/08/13 dadams +;; Bind bmkp-clone-bookmark to C-x p 2. +;; menu-bar-bookmark-map: Add bmkp-clone-bookmark. +;; 2019/05/16 dadams +;; Added: bmkp-add-bookmarks-here-menu-flag, bmkp-here-menu, bmkp-exists-bookmark-satisfying-p, +;; bmkp-exists-this-file/buffer-bookmarks-p, bmkp-bookmarks-here-menu-command-entries, +;; Add bmkp-here-menu to menu-bar-bookmark-map, Buffer-menu-mode-map, Info-mode-menu, +;; diredp-bookmark-menu or dired-mode-map. +;; Add bmkp-dired-this-dir-jump to diredp-bookmark-menu or dired-mode-map. +;; 2019/05/01 dadams +;; Bind bmkp-jump-to-list to C-x p C-l, C-x j C-l. +;; 2019/04/22 dadams +;; Bind bmkp-describe-bookmark to C-h M, bmkp-describe-bookmark-lighted-here to C-x p ?. +;; 2018/10/10 dadams +;; Bound bookmark-jump-other-frame to C-x 5 B, C-x j 5 globally, and J 5 in bookmark-list buffer. +;; 2017/10/14 dadams +;; All EWW stuff is for Emacs 25+, not Emacs 24.4+. +;; 2017/01/10 dadams +;; Applied renaming: bmkp-replace-eww-keys-flag to bmkp-eww-replace-keys-flag. +;; 2017/01/02 dadams +;; menu-bar-bookmark-map: Added menu item Store Org Link To.... +;; Typo: bmkp-replace-EWW-keys-flag -> bmkp-replace-eww-keys-flag. +;; 2016/12/11 dadams +;; Remap EWW keys to bmkp- keys. +;; 2016/11/23 dadams +;; Put :advertised-binding on several keys. +;; 2016/11/15 dadams +;; bmkp-eww-jump(-other-window): Ensure that EWW code is only for Emacs 25+. +;; 2016/11/14 dadams +;; Added bindings for bmkp-eww-jump(-other-window), including in eww-mode-map. +;; Bind bmkp-delete-bookmarks to kill-line keys (C-x p C-k, C-x p deleteline). +;; 2016/06/24 dadams +;; Added bmkp-delete-bookmarks binding for and . +;; 2016/05/15 dadams +;; dired-mode-hook: +;; If diredp-bookmark-menu is defined then use that. +;; Rename menu item: Show This Dir Using a Bookmark -> Jump to a Dired Bookmark For This Dir. +;; 2016/05/08 dadams +;; Added: bmkp-bookmark-map-prefix-key, bmkp-jump-map-prefix-key, +;; bmkp-jump-other-window-map-prefix-key, bmkp-set-map-prefix-key. +;; Removed hard-coded bindings for keymaps in ctl-x-map, ctl-x-4-map. +;; (eval-when-compile (require 'cl)) ;; case +;; 2015/01/04 dadams +;; Bind bmkp-region-jump-narrow-indirect-other-window to C-x 4 j R. +;; 2014/07/11 dadams +;; bmkp-highlight-menu: Added item Toggle Autofile Highlighting in Dired. +;; 2014/07/06 dadams +;; Removed: bmkp-options-menu. Use bmkp-bmenu-toggle-menu, and rename Toggle, not Toggle Option. +;; Removed individual toggle commands from menu-bar-bookmark-map (Bookmarks). +;; Reuse bmkp-bmenu-toggle-menu for menu-bar-bookmark-map [options]. +;; 2014/07/05 dadams +;; Moved submenu bmkp-jump-tags-menu before individual menu items. +;; 2014/03/23 dadams +;; Bind j and J in bookmark-bmenu-mode-map. Bind also j > there. +;; Add bmkp-bmenu-jump-to-marked to bmkp-jump-menu when in bookmark-list display. +;; 2013/10/29 dadams +;; Bind bookmark-set's previous keys to bmkp-bookmark-set-confirm-overwrite. +;; Bind bookmark-set to C-x r M, not C-x r m. +;; bmkp-menu-bar-set-bookmark: Use bmkp-bookmark-set-confirm-overwrite, not bookmark-set. +;; 2013/07/20 dadams +;; Moved items to new submenus: New/Update and Delete. +;; 2013/06/30 dadams +;; Bind bmkp-set-snippet-bookmark to C-x p M-w, bmkp-snippet-to-kill-ring to C-x j M-w. +;; 2013/05/28 dadams +;; Applied renaming of bmkp-edit-bookmark-name-and-file to bmkp-edit-bookmark-name-and-location. +;; 2013/04/15 dadams +;; In bmkp-set-map: Bind F to bmkp-make-function-bookmark (C-x p c F). +;; Bind C-k to bmkp-wrap-bookmark-with-last-kbd-macro (C-x p c C-k). +;; Bind s to bmkp-set-sequence (C-x p c s). +;; 2012/08/31 dadams +;; Do not bind bmkp-compilation-target-set(-all) unless defined. +;; 2012/06/26 dadams +;; Wrapped require of bookmark+-mac.el in eval-when-compile. +;; 2012/06/21 dadams +;; Try to load-library bookmark+-mac, for bmkp-menu-bar-make-toggle. +;; 2012/02/26 dadams +;; Bind: +;; bmkp-this-file/buffer-bmenu-list to C-x p , not C-x p .. +;; bmkp-(file|dired)-this-dir-jump* to C-x j . f|d not C-x j C-f|C-d. +;; bmkp-file-this-dir-*-tags(-regexp)-jump* to C-x j t . [%][*+] not C-x j t C-f [%][*+]. +;; bmkp-this-buffer-jump* to C-x j , , not C-x j .. +;; bmkp-autonamed-this-buffer-jump* to C-x j , # not C-x j # .. +;; bmkp-autonamed-jump* to C-x j # not C-x j # #. +;; bmkp-autofile-jump* in all Emacs versions. +;; bmkp-find-file(-other-window), which is new, to C-x j C-f. +;; new autofile tags jump commands bmkp-autofile-(all|some)-tags(-regexp)-jump* to +;; C-x j t a [%][*+], which was for bmkp-find-file-*-tags*. +;; bmkp-find-file-(all|some)-tags(-regexp)* to C-x j t C-f [%] [*+] not C-x j t a [%] [*+]. +;; Add to menus: bmkp-autofile-*. Rename menu items for bmkp-find-file: Find Autofile.... +;; Rename menu Bookmarked File to Find File or Autofile. For Emacs 20-21, make it a single item. +;; bmkp-jump-tags-menu, bmkp-find-file-menu: Do not add Autofile tags items for Emacs 20. +;; 2012/02/21 dadams +;; Added bindings for: bmkp-autofile-(all|some)-tags(-regexp)-jump(-other-window), +;; bmkp-find-file(-other-window) (was same as *autofile*). +;; Changed bindings: +;; *-this-dir*: . [df] (was C-d/C-f), *this-buffer*: , (was .), *find-file*tags*: C-f (was a). +;; Define *autofile* for all Emacs versions. Separate bindings from *find-file* cmds. +;; 2011/12/30 dadams +;; Added aliases: bmkp-bookmark-(data|name)-from-record. +;; Bind E to bmkp-edit-bookmark-record, not bmkp-edit-bookmark. +;; Bind r to bmkp-edit-bookmark-name-and-file, not bookmark-rename. Ditto in menu. +;; Use bmkp-get-bookmark-in-alist, not bookmark-get-bookmark in :visible conditions. +;; menu-bar-bookmark-map: Added bmkp-edit-bookmark-record. +;; bmkp-tags-menu: Added bmkp-edit-tags. +;; 2011/12/14 dadams +;; Removed conditions :enable bookmark-alist. +;; 2011/12/09 dadams +;; Commented out menu items with complex :enable conditions, replacing them with simple ones. +;; Reason: too slow, especially in Emacs 20. +;; 2011/12/05 dadams +;; menu-bar-bookmark-map: Reordered items regarding bookmark files. +;; 2011/12/03 dadams +;; Bind C-x p L to bmkp-switch-bookmark-file-create, not bmkp-switch-bookmark-file. +;; Reordered bookmark-file items in menu-bar-bookmark-map. +;; 2011/11/18 dadams +;; Bind bmkp-image-jump(-other-window) to C-x (4) j M-i. +;; bmkp-jump-menu: Add bmkp-image-jump-other-window. +;; 2011/11/15 dadams +;; Bind *-this-file/buffer*, not *-this-buffer*. +;; 2011/11/01 dadams +;; Bind alias bmkp-autofile-jump(-*), not bmkp-find-file(-*) to C-x j a, so Icicles picks up key. +;; Bind bmkp-bookmark-file-jump to C-x j y, not C-x j x. Bind bmkp-temporary-jump(-*) to C-x j x. +;; bmkp-jump-menu: Bind bmkp-(autofile|temporary)-jump-other-window. +;; 2011/10/31 dadams +;; Bind bmkp-toggle-autotemp-on-set to C-x p x. Move bmkp-set-bookmark-file-bookmark to C-x p y. +;; menu-bar-bookmark-map: Added: bmkp-toggle-autotemp-on-set. +;; 2011/10/28 dadams +;; menu-bar-bookmark-map: +;; Added: bmkp-delete-all-temporary-bookmarks, bmkp-temporary-bookmarking-mode. Reordered. +;; bmkp-options-menu: Added: bmkp-toggle-saving-menu-list-state, bmkp-toggle-saving-bookmark-file. +;; 2011/04/24 dadams +;; Added to Bookmarks menu and its Tags submenu: Purge Autofiles with No Tags. +;; 2011/04/23 dadams +;; bmkp-tags-menu: +;; Added bmkp-set-tag-value, bmkp-(add|remove|copy)-tags, bmkp-paste-(add|replace)-tags. +;; 2011/04/21 dadams +;; Bound: bmkp-copy-tags, bmkp-paste-add-tags, bmkp-paste-replace-tags. +;; 2011/04/16 dadams +;; Added: bmkp-tags-map. Bound tag commands to prefix C-x p t. +;; 2011/04/14 dadams +;; Renamed menu Jump To Bookmark to just Jump To, in menu-bar-bookmark-map. +;; 2011/04/13 dadams +;; Added: +;; bmkp-find-file-menu (bmkp-find-file(-(all|some)-tags(-regexp)(-other-window)), +;; bmkp-jump-tags-menu (what was in main, plus bmkp-find-file-*-tags-regexp*), +;; bmkp-tags-menu (list all, rename, remove from all, (un)tag a file). +;; bmkp-jump(-other-window)-map: +;; Added bmkp-find-file(-other-window) to menu. +;; Bound keys for bmkp-find-file-(all|some)-tags(-regexp)(-other-window): C-x (4) j t a... +;; 2011/04/02 dadams +;; Added bindings for (new) bmkp-autofile-set, +;; bmkp-file-this-dir-(all|some)-tags(-regexp)-jump(-other-window). +;; 2011/04/01 dadams +;; Added to bmkp-jump-menu: bmkp-(dired|file)-this-dir-jump-other-window. +;; Created from code in bookmark+-1.el. + +;;;(@* "CHANGE LOG FOR `bookmark+-lit.el'") +;; +;; 2021/09/19 dadams +;; Everywhere: Use bmkp-bmenu-buffer, not vanilla bookmark-bmenu-buffer. +;; 2021/04/16 dadams +;; bmkp-unlight-bookmark, bmkp-light-bookmarks, bmkp-cycle-lighted-this-buffer, bmkp-light-face, +;; bmkp-light-style, bmkp-light-when, bmkp-lighting-attribute, bmkp-overlay-of-bookmark: +;; Use bmkp-get-bookmark, not bookmark-get-bookmark, but in vanilla-compatible way. +;; bmkp-bookmarks-lighted-at-point, bmkp-light-bookmark, bmkp-a-bookmark-lighted-on-this-line: +;; Use bmkp-get-bookmark, not bookmark-get-bookmark. +;; 2020/07/04 dadams +;; Replaced string *Bookmark List* with bookmark-bmenu-buffer (for Emacs 28). +;; 2020/01/12 dadams +;; bmkp-lighted-jump-to-list: Raise error if no highlighted bookmarks at point. +;; bmkp-(un)light-bookmark-this-buffer: Pass non-nil USE-NIL-ALIST-P to bookmark-completing-read. +;; 2019/08/21 dadams +;; bmkp-toggle-auto-light-when-(jump|set): Fix message: symbol-name, not symbol-value. +;; 2019/05/01 dadams +;; Added bmkp-lighted-jump-to-list. +;; 2019/04/23 dadams +;; Added bmkp-tooltip-content-function. +;; bmkp-make/move-overlay-of-style: Use bmkp-tooltip-content-function. +;; 2019/04/22 dadams +;; Added bmkp-describe-bookmark-lighted-here. +;; bmkp-make/move-overlay-of-style: Put bookmark description on overlay help-echo property. +;; 2018/09/21 dadams +;; Added: bmkp--pop-to-buffer-same-window. (Added also to bookmark+-bmu.el.) +;; bmkp-lighted-jump: Use bmkp--pop-to-buffer-same-window, not switch-to-buffer. +;; 2017/01/08 dadams +;; Use the term "entry", not "property" everywhere, for bookmark entries (fields). +;; 2016/10/25 dadams +;; Added: Faces bmkp-light-autonamed-region, bmkp-light-non-autonamed-region. +;; Options bmkp-light-style-autonamed-region, bmkp-light-style-non-autonamed-region. +;; bmkp-light-styles-alist: Added Region style. +;; bmkp-make/move-overlay-of-style: +;; Added required arg BOOKMARK. Put overlay on region if region bookmark. +;; bmkp-light-bookmark, bmkp-light-bookmarks: +;; Include newly added bookmark arg in calls to bmkp-make/move-overlay-of-style. +;; bmkp-light-face: Use face bmkp-light(-non)-autonamed-region for region bookmarks. +;; bmkp-light-style: Use style bmkp-light-style(-non)-autonamed-region for region bookmarks. +;; 2016/09/10 dadams +;; bmkp-light-face, bmkp-light-style: Use bmkp-autonamed-bookmark-p. +;; 2016/06/18 dadams +;; Protected use of fringe-bitmaps with boundp (should not be necessary though). +;; 2015/04/02 dadams +;; eval-when-compile require of bookmark+-mac, for bmkp-define-show-only-command. +;; 2015/02/08 dadams +;; Renamed: bmkp-bmenu-show-only-lighted to bmkp-bmenu-show-only-lighted-bookmarks. +;; bmkp-bmenu-show-only-lighted-bookmarks: Use macro bmkp-define-show-only-command to define it. +;; 2014/07/06 dadams +;; Added: bmkp-last-auto-light-when-jump, bmkp-last-auto-light-when-set, +;; bmkp-toggle-auto-light-when-jump, bmkp-toggle-auto-light-when-set. +;; 2013/06/09 dadams +;; Added vacuous defvars to suppress free-var warnings. +;; 2013/05/15 dadams +;; Use bmkp-string-match-p instead of string-match wherever appropriate. +;; 2012/10/09 dadams +;; Made all autoload cookies explicitly load bookmark+.el(c). Should help ELPA (e.g. MELPA). +;; 2012/09/22 dadams +;; bmkp-light-bookmark(s): Put full bookmark, not name, on overlay as its bookmark property. +;; bmkp-unlight-bookmark: Test using eq against full bookmark, not using equal against name. +;; bmkp-a-bookmark-lighted-at-pos: overlay-get now returns full bookmark, so get name if needed. +;; bmkp-overlay-of-bookmark: Use bookmark, not its name, like overlay-get does now. Test with eq. +;; bmkp-light-bookmarks: Use add-to-list instead of unconditionally adding ov to ov-symb. +;; 2012/04/28 dadams +;; bmkp-make/move-overlay-of-style, bmkp-make/move-fringe: Use FRONT-ADVANCE arg for make-overlay. +;; 2011/12/30 dadams +;; Added aliases: bmkp-bookmark-(data|name)-from-record. +;; bmkp-bookmarks-lighted-at-point: Include only bookmarks in bookmark-alist. +;; bmkp-light-bookmark: Do nothing if BOOKMARK is not a bookmark or bookmark name. +;; bmkp-a-bookmark-lighted-at-pos: Return nil if no bookmark (at POS) in bookmark-alist. +;; 2011/11/15 dadams +;; Applied renaming: bmkp-this-buffer-cycle-sort-comparer to *-this-file/buffer*. +;; 2011/08/09 dadams +;; Bind icicle-unpropertize-completion-result-flag to t for all calls to completing-read. +;; 2011/04/12 +;; bmkp-cycle-lighted-this-buffer: Use bmkp-sort-omit, not bmkp-sort-and-remove-dups. +;; 2011/04/01 dadams +;; bmkp-light-bookmark(s): Don't call bookmark-handle-bookmark. Wrap with with-current-buffer. +;; 2011/01/03 dadams +;; Added autoload cookies: defcustoms and commands. +;; 2010/12/10 dadams +;; Added defalias for bookmark-name-from(-full)-record, to fix gratuitous Emacs name change. +;; 2010/09/25 dadams +;; Added: bmkp-set-lighting-for(bookmarks|(-this)-buffer). Requested by Joe Bloggs. +;; bmkp-set-lighting-for-bookmark: Added LIGHT-NOW-P arg (from prefix arg). +;; 2010/09/11 dadams +;; Removed eval-when-compile for bookmark+-bmu, bookmark+-1. +;; 2010/08/15 dadams +;; Require: bookmark.el. +;; Require when compile: bookmark+-bmu.el, bookmark+-1.el, pp+.el (soft). +;; Applied renaming of bmkp-barf-if-not-in-menu-list to bmkp-bmenu-barf-if-not-in-menu-list. +;; bmkp-light-bookmark(s): Added missing arg to throw call. +;; bmkp-light-bookmarks: Use bmkp-remove-if, not remove-if. +;; bmkp-light-bookmarks-in-region, bmkp-light-non-autonamed-this-buffer: +;; Use bmkp-remove-if-not, not remove-if-not. +;; bmkp-read-set-lighting-args: Use pp-read-expression-map only if bound (pp+.el). +;; 2010/07/03 dadams +;; bmkp-set-lighting-for-bookmark, bmkp-bmenu-set-lighting-for-marked: +;; Use *-refresh-menu-list, not *-surreptitiously-*. +;; 2010/07/01 dadams +;; Created. + +;;;(@* "CHANGE LOG FOR `bookmark+-mac.el'") +;; +;; ************************************************************************************************** +;; NOTE: If you byte-compile Bookmark+ (recommended), then WHENEVER `bookmark+-mac.el' is updated, +;; you must load `bookmark+-mac.el' (not just `bookmark+-mac.elc'), then compile it, then +;; RECOMPILE *ALL* of the other Bookmark+ source files as well. This is normal for Lisp: code +;; that depends on macros needs to be byte-compiled anew after loading the updated macros. +;; ************************************************************************************************** +;; +;; 2021/04/16 dadams +;; bmkp-define-file-sort-predicate: Use bmkp-get-bookmark, not bookmark-get-bookmark. +;; 2021/03/04 dadams +;; Removed autoload cookie for bmkp-types-alist. Its def is also in bookmark+-1.el now. +;; 2020/11/28 dadams +;; Added: bmkp-define-history-variables, funtion bmkp-types-alist. +;; 2017/03/31 dadams +;; bmkp-define-next+prev-cycle-commands: Added optional arg OTHERP. +;; 2015/04/03 dadams +;; bmkp-replace-regexp-in-string: Copied defn here - used to produce the macro code for +;; bmkp-define-show-only-command and bmkp-define-sort-command. +;; 2015/02/22 dadams +;; bmkp-menu-bar-make-toggle: Corrected doc string - just start with HELP. +;; 2015/02/08 dadams +;; Added: bmkp-define-show-only-command. +;; 2014/07/11 dadams +;; bmkp-define-sort-command: Use setq, not push, for Emacs 20. +;; 2014/07/06 dadams +;; bmkp-menu-bar-make-toggle: Redefined - no longer use menu-bar-make-toggle. Support keywords. +;; 2014/05/27 dadams +;; Added: bmkp-with-help-window. +;; 2013/04/26 dadams +;; Added: bmkp-with-bookmark-dir. (Not used currently. For user code.) +;; 2012/10/09 dadams +;; Made all autoload cookies explicitly load bookmark+.el(c). Should help ELPA (e.g. MELPA). +;; 2012/06/26 dadams +;; Moved bmkp-assoc-delete-all, bmkp-replace-regexp-in-string to bookmark+-bmu.el. +;; 2012/04/27 +;; Added: bmkp-with-output-to-plain-temp-buffer. +;; 2012/04/12 dadams +;; bmkp-define-sort-command: Do not bmkp-bmenu-goto-bookmark-named unless current-bmk (play safe). +;; 2012/04/11 dadams +;; bmkp-define-sort-command: In function def, change order to: fn, reverse-fn, unsorted. +;; 2011/12/30 dadams +;; bmkp-define-cycle-command: Applied renaming of bmkp-sort-and-remove-dups to bmkp-sort-omit. +;; bmkp-define-file-sort-predicate: Updated doc string of generated functions. +;; Added renamings of bookmark-name-from(-full)-record, bookmark-get-bookmark-record. +;; 2011/04/12 +;; bmkp-define-cycle-command: Use bmkp-sort-omit, not bmkp-sort-and-remove-dups. +;; 2011/01/03 dadams +;; Added autoload cookies: defmacro. +;; 2010/09/25 dadams +;; Added: bmkp-define-next+prev-cycle-commands. +;; 2010/09/24 dadams +;; Added: bmkp-define-cycle-command. +;; 2010/08/18 dadams +;; Removed eval-when-compile for bookmark+-(bmu|1).el. +;; 2010/08/15 dadams +;; Created, from code in other Bookmark+ files. + +;;;(@* "CHANGE LOG FOR `bookmark+.el'") +;; +;; 2021/09/19 dadams +;; Version 2021.09.19 +;; Added option bmkp-bmenu-buffer. +;; Autoload bookmark-bmenu-buffer. +;; Moved defgroup here, from bookmark+-bmu.el. Added autoload cookie. +;; 2021/04/18 dadams +;; Version 2021.04.18 +;; 2021/03/04 dadams +;; Version 2021.03.04 +;; 2021/02/12 dadams +;; Version 2021.02.12 +;; 2020/07/04 dadams +;; Version 2020.07.04 +;; Added defconst for bookmark-bmenu-buffer (Emacs 28). +;; Added defvar, make-variable-buffer-local declaration for bookmark-annotation-name (Emacs 28). +;; 2020/07/03 dadams +;; Version 2020.07.03 +;; 2020/01/22 dadams +;; Version 2020.01.22 +;; 2020/01/12 dadams +;; Version 2020.01.12 +;; 2019/04/22 dadams +;; Version 2019.04.22 +;; 2019/04/22 dadams +;; Version 2019.02.18 +;; 2018/10/17 dadams +;; Version 2018.10.17. +;; 2018/09/21 dadams +;; Version 2017.09.21. +;; 2017/03/31 dadams +;; Version 2017.03.31. Fixed cycling bookmarks across buffers. Added other-window cycling cmds. +;; 2017/02/26 dadams +;; Version 2017.02.26. Added auto-bookmarking for Info. Better EWW - thx to Charles Roelli. +;; 2016/11/14 dadams +;; Version 2016.11.14. Added support for EWW bookmarks. Thx to Charles Roelli. +;; 2015/02/22 dadams +;; Version 2015.02.22. +;; 2015/02/08 dadams +;; Version 2015.02.08 +;; 2015/01/04 dadams +;; Version 2015.01.04. +;; 2013/04/14 dadams +;; Added Version entry to header. Updated bmkp-version-number to the same thing. +;; 2012/10/09 dadams +;; Made all autoload cookies explicitly load bookmark+.el(c). Should help ELPA (e.g. MELPA). +;; 2012/06/26 dadams +;; Wrapped require of bookmark+-mac.el in eval-when-compile. +;; 2012/06/21 dadams +;; Try to load-library bookmark+-mac. Require it only if cannot load-library. +;; 2012/02/26 dadams +;; Version 3.4.0. +;; 2011/12/30 dadams +;; Version 3.3.0. +;; 2011/04/12 dadams +;; Version 3.2.2. +;; 2011/04/01 dadams +;; Require bookmark+-key.el (new). Version 3.2.1. +;; 2011/01/03 dadams +;; Added autoload cookies: defconst, command. +;; 2010/08/19 +;; bmkp-version-number: Version 3.2.0. +;; 2010/08/15 dadams +;; Require bookmark+-mac.el. +;; Do not ensure loaded before compile (not needed here now). +;; 2010/07/14 dadams +;; Version 3.1.1. +;; Moved main content of bookmark+.el to new files bookmark+-1.el and bookmark+-bmu.el. +;; 2010/07/13 dadams +;; Version 3.1.0. +;; Added redefinitions: bookmark-bmenu-(1|2)-window, bookmark-bmenu-other-window-with-mouse, +;; bookmark-bmenu-this-window, bookmark-bmenu-switch-other-window. +;; Added: bmkp-last-bookmark-file, bmkp-switch-to-last-bookmark-file. +;; Removed pre-23 version of bookmark-bmenu-switch-other-window. +;; bookmark-load: Use bmkp-last-bookmark-file when read file name. Added missing prefix arg. +;; Save old current as bmkp-last-bookmark-file. +;; bookmark-bmenu-list: If bookmark file has changed do not restore state saved from other file. +;; Save old current as bmkp-last-bookmark-file. +;; bmkp-bmenu-list-1: Do not use bmkp-bmenu-title if it is empty (""). +;; bookmark-bmenu-mode: Added to doc string: bmkp-switch-bookmark-file. +;; bookmark-bmenu-other-window: Do not bind bookmark-automatically-show-annotations (per vanilla). +;; bookmark-bmenu-show-annotation: Ensure in bmenu list and on a bookmark line. +;; bmkp-switch-bookmark-file: Use bmkp-last-bookmark-file when read file name. +;; bmkp-bmenu-define-full-snapshot-command: Set bmkp-last-bookmark-file. +;; bmkp-bookmark-description: Fixed typo: bmkp-bookmark-file-bookmark-p (not desktop). +;; bmkp-make-bookmark-file-record: Use arg file (not bmkp-non-file-filename) as filename entry. +;; +;; Added more autoload cookies. +;; 2010/07/09 dadams +;; Added: bmkp-bmenu-mark-bookmark-file-bookmarks, bmkp-bmenu-show-only-bookmark-files, +;; bmkp-bookmark-file-jump, bmkp-set-bookmark-file-bookmark, bmkp-bookmark-file-history, +;; bmkp-use-bookmark-file-create, bmkp-bookmark-file, bmkp-bookmark-file-alist-only, +;; bmkp-bookmark-file-bookmark-p, bmkp-jump-bookmark-file, bmkp-make-bookmark-file-record. +;; bmkp-types-alist, bmkp-buffer-names, bmkp-bmenu-mode-status-help, bmkp-bmenu-propertize-item, +;; bmkp-this-buffer-p, bmkp-last-specific-buffer-p, bmkp-specific-buffers-alist-only, +;; bmkp-bookmark-description, bookmark-bmenu-mode: Updated for bookmark-file bookmarks. +;; bookmark--jump-via: Added a catch, so a handler can skip all other processing when it's done. +;; bookmark-load: Final msg says whether overwritten. +;; Bound and added to menus: bmkp-set-bookmark-file-bookmark, +;; bmkp-bmenu-mark-bookmark-file-bookmarks, +;; bmkp-bmenu-show-only-bookmark-files, bmkp-bookmark-file-jump. +;; 2010/07/07 dadams +;; bookmark-handle-bookmark: Bind use-dialog-box, use-file-dialog to nil. +;; bookmark-location: From Emacs 23: Use location property and -- Unknown location --. +;; bmkp-switch-bookmark-file: Bind insert-default-directory to nil. +;; bmkp-empty-file: Expand FILE. Return FILE. +;; 2010/07/03 dadams +;; Added: bmkp-bmenu-describe-marked, bmkp-bookmark-description. +;; bmkp-describe-bookmark: Rewrote to use bmkp-bookmark-description. +;; Bound bmkp-bmenu-describe-marked to C-h >. +;; bmkp-bmenu-menubar-menu: Added bmkp-bmenu-describe-(marked|bookmark). +;; Updated doc string of bookmark-alist. +;; 2010/07/01 dadams +;; Added: bmkp-bmenu-mark-lighted-bookmarks, bmkp-bmenu-set-tag-value-for-marked, +;; bmkp-bmenu-show-only-tagged, bmkp-occur-create-autonamed-bookmarks, +;; bmkp-set-autonamed-bookmark, bmkp-set-autonamed-bookmark-at-line, +;; bmkp-set-autonamed-regexp-buffer, bmkp-set-autonamed-regexp-region, +;; bmkp-set-tag-value-for-navlist, bmkp-prompt-for-tags-flag, bmkp-menu-bar-make-toggle, +;; bmkp-same-creation-time-p, bmkp-set-tag-value-for-bookmarks, +;; bmkp(-bmenu)-highlight-menu, bmkp-options-menu. +;; Renamed: bmkp-use-region-flag to bmkp-use-region, +;; bmkp-bmenu-jump-menu to bmkp-jump-menu. +;; Removed: bmkp-cycle-this-buffer-buff (unused). +;; Soft-require new library bookmark+-lit.el. +;; Split off new file bookmark+-chg.el from bookmark+-doc.el. +;; Changed default values of faces bmkp->-mark, bmkp-t-mark. +;; bmkp-crosshairs-flag: Added :set instead of add-hook at top level. +;; bmkp-use-region: Changed from boolean to choice - added cycling-too value. +;; bookmark-set: Added INTERACTIVEP arg. Prompt for tags when bmkp-prompt-for-tags-flag. +;; Auto-highlight when set, per bmkp-auto-light-when-set. +;; bookmark--jump-via: Auto-highlight when jump, per bmkp-auto-light-when-jump. +;; Set BOOKMARK to result of bmkp-update-autonamed-bookmark. +;; Bind orig-buff when running hook. +;; bookmark-default-handler: Pass the bookmark too as an arg to bmkp-goto-position. +;; bookmark-relocate, bookmark-rename, bmkp-bmenu-list-1, bmkp-remove(-all)-tags, bmkp-add-tags: +;; Add 0 as FRAME arg to get-buffer-window. +;; bookmark-delete: Remove any highlighting on bookmark. +;; bmkp-bmenu-list-1: Add highlight-overrides indicator. +;; bmkp-completing-read-1: Added (not laxp) guard for first branch of main if. +;; bmkp-crosshairs-highlight: Assign a priority. Make the cmd a no-op for Emacs 20-21. +;; bmkp-choose-navlist-*, bmkp-navlist-bmenu-list, bmkp-jump-in-navlist*, +;; bmkp-cycle(-this-buffer*): +;; Set bmkp-current-nav-bookmark to bookmark, not to its name. +;; bmkp-update-autonamed-bookmark: Do not set bmkp-current-nav-bookmark to the name. +;; Call bmkp-refresh-menu-list even if menu list is not displayed. +;; Pass the bookmark name to bmkp-refresh-menu-list. +;; Return the updated BOOKMARK. +;; bmkp-refresh-menu-list: Set window point also. +;; bmkp-goto-position: +;; Added BOOKMARK arg. When bmkp-save-new-location-flag, update BOOKMARK. Return indicator. +;; bmkp-create-varlist-bookmark: Call bookmark-set with INTERACTIVEP arg. +;; bmkp-cycle(-this-buffer*): Added STARTOVERP arg. Pass OTHER-WINDOW, STARTOVERP to bmkp-cycle-1. +;; bmkp-cycle-1: Added STARTOVERP arg. If non-nil pop-up-frames, then inhibit showing annotation. +;; Use region only if bmkp-use-region value is cycling-too. +;; Use eq for *-list-position test. If *-list-position returns nil, then reset. +;; Use save-selected-window, unlesl OTHER-WINDOW. +;; bmkp-(next|previous)-bookmark(-this-buffer|-w32): Added STARTOVERP arg. C-u: start over at 1. +;; Bind highlight cmds: *-map: h,H,u,U,C-u,=,C-up|down. *-bmenu-*map: H+,H>+,H>H,HH,HS,H>U,HU. +;; *-jump-map: h. Bind TS in *-bmenu-*map. +;; Add bmkp-occur-create-autonamed-bookmarks to occur-mode-map as C-c b. +;; Menus: Added Highlight, Toggle Option. Added light to Jump To, Show, Mark, mouse. Reorder. +;; 2010/06/23 dadams +;; Split the change log off from file bookmark+-doc.el to new file bookmark+-chg.el. +;; 2010/06/21 dadams +;; Renamed: bmkp-toggle-autoname-bookmark-set/delete to bmkp-toggle-autonamed-bookmark-set/delete, +;; bmkp-autonamed-bookmarks-alist-only to bmkp-autonamed-this-buffer-alist-only, +;; bmkp-bookmark-autoname-p to bmkp-autonamed-bookmark-for-buffer-p, +;; Added: bmkp-autonamed-alist-only, bmkp-non-autonamed-alist-only, bmkp-autonamed-bookmark-p, +;; bmkp-completing-read-1: Use DEFAULT as default. Use just (not lax) - no non-t. +;; Use DEFAULT if empty input only if DEFAULT is non-nil. +;; bmkp-choose-navlist-of-type: Added pseudo-type "any". +;; bmkp-specific-buffers-alist-only: Exclude desktop etc. bookmarks. +;; bmkp-update-autonamed-bookmark: Arg can be a bookmark (not just name). +;; 2010/06/19 dadams +;; RENAMED bookmarkp* TO bmkp*. ***** THIS IS AN INCOMPATIBLE CHANGE ****** +;; +;; If you have existing customizations, or if you have bookmarks that have the (internal) tag +;; "bmkp-jump", then YOU MUST REPLACE occurrences of "bookmarkp" by "bmkp" EVERYWHERE. This +;; includes replacing occurrences in (1) your bookmarks file (bookmark-default-file), (2) your +;; state file (bmkp-bmenu-state-file), and (3) your command file (bmkp-bmenu-commands-file). +;; +;; Changed *-bmenu-w32-open-select binding to M-o from M-v. +;; 2010/06/11 dadams +;; Wrap all (require '* nil t) in condition-case. +;; 2010/06/07 dadams +;; Fix deskstop bookmarks for Emacs < 22. Protect: +;; *-release-lock with fboundp, *-buffer-args-list with boundp, *-dir with Emacs version #, +;; 2010/05/30 dadams +;; Added: bookmarkp-(next|previous)-bookmark-w32(-repeat). Bound to C-x p (next|prior). +;; 2010/05/29 dadams +;; *-bmenu-list, *-choose-navlist-from-bookmark-list, *-bmenu-define(-full-snapshot)-command, +;; *-save-menu-list-state, -make-bookmark-list-record: +;; Add/restore bookmarkp-bmenu-filter-pattern to/from state. +;; *-jump-bookmark-list: Set bookmarkp-latest-bookmark-alist to bookmark-alist. +;; Reordered Bookmark menu and added items: +;; Set Bookmark, Delete Autonamed Bookmark, Delete All Autonamed Bookmarks Here, +;; Delete Bookmarks Here, Delete Bookmark, Rename Bookmark, Bookmark List for This Buffer, +;; Bookmark List for Navlist, Set Navlist to Bookmarks of Type, +;; Set Navlist from Bookmark-List Bookmark, Insert Bookmark Contents, Insert Bookmark Location. +;; Added to Bookmark+ menu: Set Navlist *. +;; Added to bookmarkp-bmenu-jump-menu: In Navigation List. +;; Added :enable entries for menu items. +;; Updated bookmark-bmenu-mode doc string for cycling, navlist, and options. +;; Corrected bindings of bookmarkp-jump-in-navlist(-other-window). +;; 2010/05/26 dadams +;; Added: +;; bookmarkp-choose-navlist-(from-bookmark-list|of-type), bookmarkp-crosshairs-highlight, +;; bookmarkp-cycle(-this-buffer)(-other-window), bookmarkp-delete-bookmarks, +;; bookmarkp-jump-in-navlist(-other-window), bookmarkp-navlist-bmenu-list, +;; bookmarkp-(next|previous)-bookmark(-this-buffer)(-repeat), +;; bookmarkp-toggle-autoname-bookmark-set/delete, bookmarkp-autoname-bookmark(-function), +;; bookmarkp-autonamed-bookmarks-alist-only, bookmarkp-autoname-format, +;; bookmarkp-bookmark-autoname-p, bookmarkp-crosshairs-flag, +;; bookmarkp-this-buffer-cycle-sort-comparer, bookmarkp-current-bookmark-list-state, +;; bookmarkp-cycle-1, bookmarkp-list-position, bookmarkp-position-cp, +;; bookmarkp-current-nav-bookmark, bookmarkp-cycle-this-buffer-buff, bookmarkp-nav-alist, +;; bookmarkp-update-autonamed-bookmark, bookmarkp-delete-all-autonamed-for-this-buffer. +;; Bound: +;; bookmarkp-choose-navlist-from-bookmark-list, bookmark-insert-location, +;; bookmarkp-navlist-bmenu-list, bookmarkp-choose-navlist-of-type, bookmarkp-delete-bookmarks, +;; bookmarkp-toggle-autoname-bookmark-set/delete, bookmarkp-jump-in-navlist(-other-window), +;; bookmarkp-(next|previous)-bookmark(-this-buffer)-repeat. +;; bookmark--jump-via: Update the name and position of an autonamed bookmark. +;; 2010/05/22 dadams +;; *-this-buffer-p: Return nil for bookmarks not really associated with a buffer. +;; *-default-handler, *-goto-position: Forgot comma to eval file-name when no-such-file error. +;; *-show-annotation: Bind buffer-read-only to nil for updating. +;; 2010/05/19 dadams +;; Added: bookmarkp-this-buffer-bmenu-list. Bound to `C-x p .'. +;; menu-bar-bookmark-map: +;; Added bookmarkp-this-buffer-bmenu-list. Added separators. +;; Added vanilla items edit, write, load, to impose order. Renamed item edit. +;; 2010/05/16 dadams +;; bookmark-set: Quoted history arg. Thx to S. Nemec. +;; bookmarkp-bmenu-define-full-snapshot-command: Use quote comma, not quote, for *-specific-*. +;; 2010/05/15 dadams +;; Replace *same-(buffer|file)-jump* by *specific-(buffers|files)-jump*: read multiple buff/files. +;; Renamed: *same-(buffer|file)* to *-last-specific-(buffer|file)* for pred, alist, and var. +;; Renamed: *same-(buffer|file)* to *specific-(buffer|file)* for hist, *types*, mark/show cmds. +;; Renamed: *-selected-buffers-alist* to *-specific-buffers-alist*. +;; Added: *-specific-files-alist*, *-(all|some)-tags(-regexp)-alist-only. +;; *-completing-read-(buffer|file)-name: Use (buffer|file)-name-history, not *-same-*-history. +;; *-read-tags-completing: Rewrote to correctly handle cons and string tags, error handling, etc. +;; *-bmenu-(add|remove)-tags-*-marked: Error handling. +;; *(all|some)-tags(-regexp)-jump*: Use *-(all|some)-tags(-regexp)-alist-only. +;; 2010/05/11 dadams +;; Added: bookmarkp-bmenu-mark-same-(buffer|file)-bookmarks, bookmarkp-this-(buffer|file)-p, +;; bookmarkp-this-(buffer|file)-alist-only, bookmarkp-bmenu-show-only-same-(buffer|file), +;; bookmarkp-completing-read-(buffer|file)-name, bookmarkp-same-(buffer|file)-history, +;; bookmarkp-(same|this)-(buffer|file)-alist-only, bookmarkp-last-same-(buffer|file), +;; bookmarkp-(same|this)-(buffer|file)-jump(-other-window), bookmarkp-(buffer|file)-names, +;; bookmarkp-same-(buffer|file)-as-last-p, bookmarkp-other-window-pop-to-flag, +;; bookmarkp-select-buffer-other-window. +;; Use bookmarkp-select-buffer-other-window instead of switch-to-buffer-other-window everywhere. +;; Bound = (b|f) (M|S), C-x j (=|.) (b|f) to (same|current)-(buffer|file) commands. +;; *-types-alist: Handle same-(buffer|file) too. +;; *-bmenu-list, *-bmenu-define-full-snapshot-command, *-save-menu-list-state: +;; Handle bookmarkp-last-same-(buffer|file) as part of state. +;; 2010/05/05 dadams +;; bookmarkp-create-varlist-bookmark, bookmarkp-make-varlist-record: +;; Added optional arg BUFFER-NAME. +;; bookmark-alist: Corrected doc string wrt BUFFER-NAME and region context strings. +;; 2010/05/04 dadams +;; Added: bookmarkp-create-varlist-bookmark. +;; bookmarkp-jump-varlist: If bookmark's buffer doesn't exist, use current buffer and show msg. +;; 2010/04/24 adams +;; Added: bookmarkp-bmenu-show-only-varlists, bookmarkp-set-restrictions-bookmark, +;; bookmarkp-set-varlist-bookmark, bookmarkp-varlist-jump, bookmarkp-varlist, +;; bookmarkp-jump-varlist, bookmarkp-make-varlist-record, bookmarkp-printable-p, +;; bookmarkp-printable-vars+vals, bookmarkp-read-variables-completing, +;; bookmarkp-read-variable, bookmarkp-varlist-alist-only, bookmarkp-varlist-bookmark-p, +;; bookmarkp-varlist-history. +;; Bound bookmarkp-bmenu-show-only-varlists to V S, bookmarkp-varlist-jump to C-x j v (and menu). +;; *-types-alist: Added bookmarkp-varlist-history. +;; *-bmenu-mode-status-help, *-bmenu-propertize-item, *-describe-bookmark: Handle varlist bmks. +;; *-bmenu-w32-open-select: Changed binding to M-v from V. +;; *-bmenu-mode: Updated doc string. +;; 2010/04/17 dadams +;; bookmark-set: Numeric prefix arg means use all bookmarks as completion candidates. +;; Simplified the prompt. +;; bookmarkp-completing-read-1: +;; Use icicle-transform-multi-completion in icicle-delete-candidate-object +;; Ensure loaded before byte-compile (put a require after provide). +;; Move bookmarkp-replace-regexp-in-string before macro bookmarkp-define-sort-command (uses it). +;; bookmarkp-bmenu-w32-open-with-mouse, bookmarkp-bmenu-mouse-3-menu: +;; Use with-current-buffer, not save-excursion of set-buffer. +;; bookmarkp-make-dired-record, bookmarkp-jump-dired: Use dolist, not mapcar (just side effect). +;; bookmarkp-(some|all)-tags-jump(-other-window): Removed extraneous arg in error call. +;; 2010/04/16 dadams +;; Added: bookmarkp-completing-read-1, bookmarkp-completing-read-lax, +;; bookmarkp-selected-buffers-alist-only. +;; bookmark-set: Use bookmark-completing-read-lax w/ buffer's bookmarks, not read-from-minibuffer. +;; bookmark-completing-read: Define using bookmarkp-completing-read-1. +;; 2010/04/09 dadams +;; bookmarkp-edit-bookmark: Update dired-directory property along with filename property. +;; 2010/03/28 dadams +;; bookmarkp-goto-position: Don't funcall bookmarkp-jump-display-function if it is nil. +;; 2010/03/28 dadams +;; bookmark-default-handler: Don't funcall bookmarkp-jump-display-function if it is nil. +;; 2010/03/27 dadams +;; Changed the customization group from bookmarkp to bookmark-plus. +;; Moved doc and change history from bookmark+.el to this new file, bookmark+-doc.el. +;; bookmarkp-commentary-button: Use bookmark+-doc.el, not bookmark+.el. +;; 2010/03/17 dadams +;; Added: bookmarkp-toggle-bookmark-set-refreshes, bookmarkp-refresh-latest-bookmark-list, +;; bookmarkp-after-set-hook. +;; 2010/03/16 dadams +;; Fixed parens placement (typo) for last change to define *-jump-woman for Emacs 20. +;; 2010/03/11 dadams +;; Define bookmarkp-jump-woman also for Emacs 20 (just raise an error). +;; *-show-annotation: Typo: bookmark -> bmk-name. +;; 2010/03/10 dadams +;; Added: bookmarkp-bookmark-creation-cp, bookmarkp-bmenu-sort-by-creation-time (bind: s0, menu). +;; *-make-record-default: Add entry: created. +;; *-describe-bookmark: Add creation time to description. +;; 2010/03/03 dadams +;; *-sort-and-remove-dups: Do not set bookmarkp-sorted-alist to the result. +;; *-bmenu-list-1: Set bookmarkp-sorted-alist to the result of calling *-sort-and-remove-dups. +;; 2010/03/02 dadams +;; Added: bookmarkp-sorted-alist. +;; *-bmenu-list-1: Use bookmarkp-sorted-alist. +;; *-sort-and-remove-dups: Set bookmarkp-sorted-alist to the result. +;; All *-cp (and hence *-define-file-sort-predicate): +;; Accept bookmark names as args, in addition to bookmarks. +;; bookmark-alpha-p: Don't use bookmarkp-make-plain-predicate, to avoid infinite recursion. +;; 2010/02/28 dadams +;; Added: bookmarkp-send-bug-report. +;; bookmarkp-bmenu-mode-status-help: Rewrote to provide only Bookmark+ help. Added help buttons. +;; Fixed Commentary typos. +;; 2010/02/26 dadams +;; Added: bookmarkp-desktop-change-dir, bookmarkp-desktop-kill, bookmarkp-desktop-delete. +;; *-jump-desktop: Call *-desktop-change-dir. +;; *-read-bookmark-for-type: Added optional arg ACTION. +;; 2010/02/24 dadams +;; *-bmenu-list: Handle case null last-bookmark-file (due to old file format). Thx to Seb Luque. +;; *-make-record-default: protect dired-buffers with boundp. Thx to Janek Schwarz. +;; 2010/02/16 dadams +;; bookmarkp-define-sort-command: Add msg suffix about repeating. +;; bookmarkp-msg-about-sort-order: Added optional arg SUFFIX-MSG. +;; 2010/02/15 dadams +;; Added: bookmark-bmenu-switch-other-window (redefinition for Emacs 20-22). +;; *-bmenu-mode: Added redefinition, instead of advising. +;; *-send-edited-annotation, *-relocate, *-rename, *-bmenu-refresh-menu-list, +;; *-remove(-all)-tags, *-add-tags: +;; Refresh the menu list, to pick up changes. +;; *-refresh-menu-list: Added optional arg BOOKMARK: go to it. +;; Do not bind bookmark-bmenu-relocate unless it's defined. +;; *-handler-cp: Respect case-fold-search. +;; 2010/02/14 dadams +;; Renamed bookmark-bmenu-list-1 to bookmarkp-bmenu-list-1. +;; Added faces: bookmarkp-(a|t|>|D)-mark, bookmarkp-heading (don't use bookmark-menu-heading). +;; Added redefinitions: bookmark-send-edited-annotation, bookmark(-bmenu)-show-annotation, +;; bookmark-show-all-annotations. +;; *-bmenu-mark, *-bmenu-delete, *-bmenu-list-1: Add faces to marks. +;; *-bmenu-list-1 and everywhere: Get rid of "% " before menu-list title. +;; *-bmenu-list-1: Use "a", not "*", as annotation mark. +;; Add "t" mark for tags. Add an extra space before bookmark name. +;; *-bmenu-marks-width: change value from 2 to 4, for the tags column and the extra space. +;; 2010/02/13 dadams +;; Added: bookmarkp-desktop-history, +;; bookmarkp-desktop-jump (bound to C-x j K; added to menu), +;; bookmarkp-bookmark-list-jump (bound to C-x j B; added to menu), +;; bookmarkp-bookmark-list-alist-only, bookmarkp-bookmark-list-history. +;; *-types-alist: Added entries for desktops and bookmark-lists. +;; *-describe-bookmark: Added optional arg, to show full (internal) info. +;; Bind it to ? in bookmark-map. +;; *-jump-bookmark-list: Pop to the bookmark-list (to show it). +;; *-bmenu-mark-w3m-bookmarks: Typo: wrong predicate. +;; *(-bmenu)-remove-all-tags: Raise error if no tags to remove. +;; *-bmenu-remove-all-tags: Require confirmation if interactive. +;; *-bmenu-remove-tags: Added optional arg MSGP. +;; Menus: Added "..." as needed. +;; *-bmenu-mouse-3-menu: Guard bookmark-bmenu-relocate with fboundp. +;; 2010/02/12 dadams +;; Added: bookmarkp-bmenu-define-jump-marked-command. Bound to M-c and added to menu. +;; Changed bookmarkp-toggle-saving-bookmark-file binding to M-~ (M-s conflicts w isearch-multi). +;; Updated bookmark-bmenu-mode doc string. +;; 2010/02/11 dadams +;; Added: bookmarkp-types-alist, +;; bookmarkp-(dired|gnus|info|man|region|w3m|(non-|local-|remote-)file)-history. +;; bookmark-completing-read: Added optional HIST arg. +;; *-(relocate|rename|insert(-location)): Added bookmark default for interactive use. +;; *-jump-dired: Handle bookmarkp-jump-display-function. +;; *-read-bookmark-for-type: Added optional HIST arg. +;; *-jump-to-type(-other-window), +;; *-(dired|file|gnus|info|man|region|w3m|(local-|non-|remote-)file)-jump*(-other-window): +;; Use type-specific history var. +;; 2010/02/09 dadams +;; Added: bookmarkp-get-tag-value. +;; bookmark--jump-via: Handle special bookmark tag bookmarkp-jump. +;; 2010/02/08 dadams +;; Renamed: bookmarkp-bmenu-dired-marked-local to bookmarkp-bmenu-dired-marked. +;; bookmarkp-bmenu-dired-marked: Handle remote bookmarks if Emacs > 23.1. +;; Support tags with values. +;; Added: bookmarkp-tag-name, bookmarkp-full-tag, bookmarkp(-bmenu)-set-tag-value. +;; Renamed variable (not fn) bookmarkp-tags-list to bookmarkp-tags-alist. +;; Use bookmarkp-full-tag everywhere for tag completion. +;; *-has-tag-p: Use assoc-default, not member. +;; *-read-tag(s)-completing: CANDIDATE-TAGS is now an alist. +;; *-list-all-tags: Added optional arg FULLP (prefix arg). +;; *-tags-list: Added optional arg NAMES-ONLY-P. +;; *-(add|remove|rename)-tags: Use copy-alist, not copy-sequence. Alist, not list, membership. +;; *-rename-tag: Raise error if no tag with old name. +;; *-bmenu-mark-bookmarks-tagged-regexp, *-regexp-filtered-tags-alist-only, *-describe-bookmark, +;; *-(all|some)-tags-regexp-jump(-other-window): +;; Use bookmarkp-tag-name. +;; *-bmenu-mark/unmark-bookmarks-tagged-(all|some)/(none|not-all), *-define-tags-sort-command: +;; Use assoc-default, not member. +;; Added: bookmarkp-bmenu-add-tags, bookmarkp-bmenu-remove(-all)-tags. +;; *-bmenu-mouse-3-menu: Use bookmarkp-bmenu-add-tags, bookmarkp-bmenu-remove(-all)-tags. +;; Added bookmarkp-bmenu-set-tag-value. +;; *-bmenu-mark-bookmarks-satisfying: Made it a command (interactive). +;; 2010/02/07 dadams +;; *-write-file: Corrected handling of ALT-MSG. +;; Cleanup. +;; *-remove-tags: Don't call *-get-tags twice. +;; *-bmenu-(un)mark-bookmarks-tagged(-not)-(all|none|some): +;; Don't duplicate what bookmarkp-read-tags-completing does. +;; *-add-tags, *-remove-tags(-from-all): TAGS arg must be a list from the beginning. +;; *-remove-tags-from-all, *-rename-tag: Use bookmark-all-names - don't mapcar car over alist. +;; *-all-tags-regexp-jump: Corrected to use same pred as *-all-tags-regexp-jump-other-window. +;; *-(some|all)-tags-jump(-other-window): Use bookmarkp-has-tag-p - don't repeat the definition. +;; *-read-tag(s)-completing: Removed unnecessary or. +;; 2010/02/06 dadams +;; *-write-file, *-empty-file: Corrected handling of ALT-MSG. +;; 2010/02/05 dadams +;; Added: bookmarkp-same-file-p, bookmarkp-empty-file. +;; Bound bookmarkp-empty-file to C-x p 0, and added it to menus. +;; *-bmenu-list, *-switch-bookmark-file: Use bookmarkp-same-file-p. +;; bookmark-write-file: Added optional ALT-MSG arg. +;; 2010/02/04 dadams +;; Added: bookmarkp-bmenu-omit, bookmarkp-list-all-tags. Added to mouse-3 menu, Tags menus. +;; 2010/02/01 dadams +;; Added: bookmarkp-current-bookmark-file, bookmarkp-switch-bookmark-file, +;; (redefinition of) bookmark-load, (redefinition of) bookmark-save, +;; bookmarkp-toggle-saving-bookmark-file, bookmarkp-last-save-flag-value. +;; *-bmenu-list: Restore bookmarkp-current-bookmark-file if appropriate. +;; *-bmenu-mode-status-help: Show bookmarkp-current-bookmark-file. +;; *-bmenu-define-full-snapshot-command, *-save-menu-list-state: +;; Save bookmarkp-current-bookmark-file. +;; Bound bookmarkp-switch-bookmark-file to L and C-x r L. Added both load commands to both menus. +;; *-toggle-saving-menu-list-state: Changed binding to M-l. Error if init value is nil. +;; Bound *-toggle-saving-bookmark-file to M-s and added to menu. +;; Added bookmark-write to bookmarkp-bmenu-menubar-menu (Save As). +;; bookmarkp-bmenu-menubar-menu: Added :help strings everywhere. +;; bookmarkp-bmenu-mode-status-help: Added face legend. +;; 2010/01/31 dadams +;; Added: bookmarkp-tags-list, bookmarkp-read-tag-completing, bookmarkp-use-w32-browser-p, +;; bookmarkp-bmenu-w32-open(-select|-with-mouse). Bind *-w32* to M-RET, V, M-mouse-2. +;; *-default-handler: Call w32-browser if bookmarkp-use-w32-browser-p. +;; *-bmenu-unomit-marked: Don't try to return to original position (duh). +;; *-bmenu-goto-bookmark-named: Use eobp as loop condition. Call bookmark-bmenu-ensure-position. +;; *-read-tags-completing: +;; Added arg UPDATE-TAGS-LIST-P. Call bookmark-maybe-load-default-file. +;; Use bookmarkp-tags-list if CANDIDATE-TAGS is nil. Update that var if UPDATE-TAGS-LIST-P. +;; *-(add|remove)-tags: Added arg NO-CACHE-UPDATE-P. If nil, call bookmarkp-tags-list. +;; *-remove-tags-from-all, *-rename-tag, *-bmenu-(add|remove)-tags-(to|from)-marked: +;; Call bookmarkp-tags-list. +;; *-remove-tags-from-all: Pass nil as tags arg to bookmarkp-read-tags-completing. +;; *-rename-tag: Use bookmarkp-read-tag-completing, not read-string. +;; 2010/01/29 dadams +;; bookmarkp-describe-bookmark: Handle desktop bookmarks specifically. +;; Added: bookmarkp-menu-popup-max-length. +;; bookmark-completing-read: Use bookmarkp-menu-popup-max-length. +;; bookmarkp-bmenu-state-file: Added missing default value for const. +;; Don't add jump-other entry to menu-bar-bookmark-map (just use Jump To submenu). +;; 2010/01/28 dadams +;; bookmarkp-(all|some)-tags(-regexp)-jump(-other-window): Error if no bookmarks with the tags. +;; bookmarkp-(all|some)-tags-jump(-other-window): Handle case where user enters no tags. +;; Use :advertised-binding property for bookmark-jump(-other-window). +;; Added: bookmarkp-bmenu-jump-menu. +;; Added bookmarkp-bmenu-jump-menu to menu-bar-bookmark-map and bookmarkp-bmenu-menubar-menu. +;; 2010/01/27 dadams +;; Added: bookmarkp-every, bookmarkp-(all|some)-tags(-regexp)-jump(-other-window). +;; 2010/01/26 dadams +;; Added: bookmarkp-bmenu-dired-marked-local. Bound to M-d >. +;; 2010/01/23 dadams +;; Added: bookmarkp-handler-cp, bookmarkp-desktop-no-save-vars, bookmarkp-set-desktop-bookmark, +;; bookmarkp-make-desktop-record, bookmarkp-jump-desktop, bookmarkp-desktop-read, +;; bookmarkp-desktop-alist-only, bookmarkp-desktop-bookmark-p, +;; bookmarkp-bmenu-mark-desktop-bookmarks, bookmarkp-bmenu-show-only-desktops, +;; face bookmarkp-desktop. +;; bookmarkp-bmenu-sort-by-bookmark-type: Add bookmarkp-handler-cp to the list (last). +;; bookmarkp-bmenu-propertize-item: Add face bookmarkp-desktop for desktop bookmarks. +;; Bound: bookmarkp-set-desktop-bookmark to C-x p K, C-x r K, +;; bookmarkp-bmenu-mark-desktop-bookmarks to K M (and Mark menu), +;; bookmarkp-bmenu-show-only-desktops to K S (and Show menu). +;; bookmark-bmenu-mode doc string: Updated for new commands. +;; Added autoload cookies for all defcustoms. +;; 2010/01/20 dadams +;; Added: bookmarkp-bmenu-mode-status-help. Bound to C-h m, ?. +;; 2010/01/19 dadams +;; bookmarkp-remote-file-bookmark-p: Include remote Dired bookmarks. Thx to Simon Harrison. +;; Added: bookmarkp-describe-bookmark-internals, bookmarkp-bmenu-describe-this+move-(down|up), +;; defalias for list-bookmarks. +;; bookmarkp-describe-bookmark: Reformatted help output. Added more info about Dired bookmarks. +;; bookmarkp-bmenu-describe-this-bookmark: +;; C-u calls bookmarkp-describe-bookmark-internals. Bound also to C-h C-RET. +;; 2010/01/18 dadams +;; Added: bookmarkp-dired-subdirs. +;; bookmarkp-make-dired-record, bookmarkp-jump-dired: Handle inserted and hidden dirs. +;; bookmarkp-jump-dired: Use expand-file-name, not concat. +;; 2010/01/17 dadams +;; Added: +;; bookmarkp-jump(-other-window)-map, bookmarkp-jump-1, bookmark-all-names (redefined), +;; bookmarkp-read-bookmark-for-type, bookmarkp-dired-jump-current(-other-window), +;; bookmarkp-(dired|(local-|remote-|non-)file|gnus|info|man|region|w3m)-jump(-other-window), +;; bookmarkp-jump-to-type(-other-window). +;; bookmark-jump(-other-window): Use bookmarkp-jump-1. +;; bookmark-completing-read: Added optional args ALIST and PRED. +;; bookmarkp-default-bookmark-name: Added optional arg ALIST. +;; 2010/01/14 dadams +;; bookmark-bmenu-surreptitiously-rebuild-list: Put back save-excursion & save-window-excursion. +;; 2010/01/02 dadams +;; Renamed *-bmenu-check-position to *-bmenu-ensure-position, per Emacs 23.2. Added defalias. +;; 2010/01/01 dadams +;; *-bmenu-(un)mark, *-bmenu-other-window, *-bmenu-rename: Call bookmark-bmenu-check-position. +;; *-bmenu-delete: Don't call bookmark-bmenu-check-position again at end. +;; *-bmenu-edit-bookmark: Call bookmark-bmenu-check-position at beginning, not end. +;; 2009/12/30 dadams +;; Added: bookmarkp-bmenu-header-lines, bookmarkp-bmenu-marks-width. Use everywhere. +;; 2009/12/29 dadams +;; Added: bookmarkp-make-bookmark-list-record, bookmarkp-jump-bookmark-list, face +;; bookmarkp-bookmark-list. +;; *-bmenu-propertize-item: Highlight bookmark-list bookmarks. +;; *-bmenu-refresh-menu-list: Set bookmarkp-latest-bookmark-alist to refreshed list. +;; Face *-local-directory: Made dark background version the inverse of light. +;; *-bmenu-list-1: Use eq, not equal, test for bookmarkp-omitted-alist-only as filter fn. +;; *-bmenu-define(-full-snapshot)-command: Include bookmarkp-bmenu-omitted-list in saved state. +;; 2009/12/26 dadams +;; Added: bookmarkp-bmenu-omitted-list, bookmarkp-bmenu-show-only-omitted, bookmarkp-unomit-all, +;; bookmarkp-bmenu-omit/unomit-marked, bookmarkp-bmenu-(un-)omit-marked, +;; bookmarkp-omitted-alist-only. +;; Bind *-bmenu-omit/unomit-marked, *-bmenu-show-only-omitted, *-unomit-all to O>,OS,OU. +;; Added omit/un-omit stuff to Bookmark+ menu. +;; bookmarkp-remove-assoc-dups, bookmarkp-sort-and-remove-dups: Added optional arg OMIT. +;; bookmark-delete: Update bookmarkp-bmenu-omitted-list. +;; bookmarkp-save-menu-list-state, bookmark-bmenu-list: +;; Save/restore bookmarkp-bmenu-omitted-list as part of state. +;; bookmark-bmenu-list-1: Treat omitted list when bookmarkp-omitted-alist-only. +;; bookmarkp-marked-bookmark-p: Arg can now be a bookmark (or a bookmark name). +;; bookmarkp-bmenu-unmark-all: Start by going forward 2 lines, not 1, if user hit RET. +;; bookmarkp-bmenu-make-sequence-from-marked: +;; Added optional arg DONT-OMIT-P. If nil, omit marked bookmarks. +;; If the seq bookmark already exists, prompt to add to it or replace it. +;; Go to the new bookmark in the menu list. +;; 2009/12/15 dadams +;; Added: bookmarkp-sequence-jump-display-function, bookmarkp-sequence, bookmarkp-function, +;; bookmarkp-bmenu-make-sequence-from-marked, bookmarkp-jump-sequence, +;; bookmarkp-sequence-bookmark-p, bookmarkp-make-function-bookmark, +;; bookmarkp-jump-function, bookmarkp-function-bookmark-p. +;; bookmarkp-describe-bookmark: Update for sequence and function bookmarks. +;; bookmark-bmenu-list: Use condition-case when read from bookmarkp-bmenu-state-file. +;; Bind emacs-lisp-mode-hook to nil. +;; bookmark-bmenu-surreptitiously-rebuild-list: Use save-current-buffer. +;; bookmarkp-bmenu-propertize-item: Add faces to function and sequence bookmarks. +;; bookmarkp-bmenu-menubar-menu: Add *-make-sequence-*-from-marked, *-make-function-bookmark. +;; bookmark--jump-via: Call *-record-visit with BATCH arg, to preserver point in menu list. +;; bookmark-bmenu-list-1: fit-frame only if buffer is *Bookmark List*. +;; 2009/12/13 dadams +;; *-alist-only: Call bookmark-maybe-load-default-file. +;; 2009/12/11 dadams +;; Added: bookmarkp-list-defuns-in-commands-file, bookmarkp-remove-dups. +;; 2009/12/06 dadams +;; Added: bookmarkp-bmenu-mouse-3-menu (bound to mouse-3), +;; bookmarkp-bmenu-(menubar|define-command|sort|show|tags|mark)-menu. +;; bookmark-bmenu-delete: Remove newly flagged bookmark from bookmarkp-bookmark-marked-list. +;; bookmarkp-define-tags-sort-command: Save macroexpanded definition in +;; bookmarkp-bmenu-commands-file. +;; 2009/12/04 dadams +;; Added: bookmarkp-bmenu-define-full-snapshot-command (bound to C), +;; bookmarkp-define-tags-sort-command. +;; bookmarkp-bmenu-mark-bookmarks-tagged-regexp: Removed extra forward-line if we mark line. +;; 2009/12/03 dadams +;; Added: bookmarkp-bmenu-define-command (bound to c), bookmarkp-bmenu-commands-file. +;; bookmark-bmenu-list: Read bookmarkp-bmenu-commands-file. +;; bookmarkp-sort-and-remove-dups: Bug fix - return the list even when null sort function. +;; 2009/11/01 dadams +;; Added: *-bmenu-check-position (redefinition), bmkext-jump-* defaliases. +;; *-(w3m|man|gnus)-bookmark-p: Recognize the aliases. +;; *-jump-man: Bind Man-notify-method. +;; *-bmenu-goto-bookmark-named: Check the text property, instead of searching. +;; *-bmenu-bookmark: Wrap in condition-case. +;; 2009/10/31 dadams +;; Added: bookmark-bmenu-list-1. bookmarkp-toggle-saving-menu-list-state (C-t), +;; bookmarkp-bmenu-state-file, bookmarkp-bmenu-first-time-p, +;; bookmarkp-last-bmenu-(bookmark|state-file), bookmark-exit-hook-internal +;; (redefinition), bookmarkp-save-menu-list-state. +;; bookmark-bmenu-list: Restore menu-list state if appropriate. Call bookmark-bmenu-list-1. +;; bookmarkp-bmenu-quit: If *-bmenu-state-file is non-nil, save the state. +;; bookmark-write-file: Use case, not cond. +;; bookmark-set: Use command name as default for man-page bookmark name. +;; bookmark-delete: Update bookmarkp-latest-bookmark-alist. +;; 2009/10/28 dadams +;; Renamed: bookmarkp-bookmark-marked-p to bookmarkp-marked-bookmark-p +;; bookmarkp-bmenu-sort-by-gnus-thread to bookmarkp-bmenu-sort-by-Gnus-thread. +;; Added: bookmarkp-man, bookmarkp-make-(wo)man-record, bookmarkp-jump-(wo)man, +;; bookmarkp-man-bookmark-p, bookmarkp-bmenu-mark-man-bookmarks, +;; bookmarkp-bmenu-show-only-man-pages, bookmarkp-man-alist-only. +;; *-bmenu-propertize-item: Handle (wo)man bookmarks. Use bookmarkp-info-bookmark-p. +;; *-regexp-filtered-*: Use bookmarkp-remove-if-not. +;; *-write-file: Remove text properties from file name also. +;; *-regexp-filtered-(tags|(bookmark|file)-name)-alist-only: Use *-remove-if-not. +;; 2009/10/26 dadams +;; Added: bookmarkp-bmenu-mark-*-bookmarks, bmenu-mark-bookmarks-satisfying. +;; Bound those and *-show-only-* accordingly. +;; bookmarkp-file-alist-only: Redefined to just use *-file-bookmark-p. +;; 2009/10/25 dadams +;; bookmarkp-bmenu-propertize-item: Put bookmark name on line as text property. +;; bookmark-bmenu-bookmark: Get bookmark name from text property bookmarkp-bookmark-name. +;; Removed: bookmarkp-latest-sorted-alist. +;; bookmark-bmenu-list: Use bookmarkp-bmenu-title only if defined. +;; 2009/10/21 dadams +;; Added: bookmarkp-barf-if-not-in-menu-list. Use in place of its body. +;; Added: bookmarkp-bmenu-mark-bookmarks-tagged-regexp. Bound to T m %. +;; Added: bookmarkp-record-visit. Use in *--jump-via. Replaces next two removals. +;; Removed: bookmarkp-add-or-update-time, bookmarkp-increment-visits. +;; Renamed: *-record-(end|front|rear)-context(-region)-string'. +;; New names: bookmarkp-(end-)position-(pre|post)-context(-region). +;; *-bmenu-describe-this-bookmark: Added *-barf-if-not-in-menu-list. +;; *-bmenu-(un)mark-all, *-bmenu-regexp-mark, *-bmenu-toggle-marks: +;; Removed with-current-buffer. +;; 2009/10/20 dadams +;; Added: bookmarkp-bmenu-filter-function, bookmarkp-bmenu-title. +;; Removed: bookmarkp-bmenu-called-from-inside-p. +;; *-bmenu-list: +;; Removed TITLE arg. Get title from bookmarkp-bmenu-title or default. +;; Use interactive-p and absence of menu list, not *-bmenu-called-from-inside-p, as the +;; criterion for removing marks. Fixes bugs such as bookmark creation removing marks. +;; *-define-sort-command, *-bmenu-execute-deletions, *-increment-visits, +;; *-add-or-update-time, *-bmenu-show-only-*, *-bmenu-show-all, +;; *-bmenu-refresh-menu-list, *-bmenu-toggle-show-only-(un)marked, +;; *-bmenu-filter-alist-by-regexp, *-bmenu-reverse(-multi-sort)-order, +;; *-bmenu-change-sort-order: +;; Do not bind or set *-called-from-inside-p. +;; *-bmenu-show-only-*, *-bmenu-show-all, *-bmenu-filter-alist-by-regexp: +;; Set *-bmenu-filter-function, *-bmenu-title. +;; *-bmenu-show-all: +;; Set *-latest-bookmark-alist to bookmark-alist. +;; *-bmenu-refresh-menu-list: Fix so that it in fact refreshes. +;; Do not use *-bmenu-surreptitiously-rebuild-list and *-bmenu-check-position. +;; Bind bookmark-alist to last alist (filtered or not), and call *-bmenu-list. +;; *-bmenu-surreptitiously-rebuild-list: +;; Do not use save*-excursion. Do not get current title and pass it to *-bmenu-list. +;; *-file-alist-only: +;; Removed optional arg. We have *-local-file-alist-only for that. +;; *-regexp-filtered-alist-only, *-bmenu-filter-alist-by-regexp: +;; Remove REGEXP arg - use bookmarkp-bmenu-filter-pattern. +;; *-bmenu-filter-incrementally: +;; Raise error if not in *Bookmark List*. +;; Use just bookmarkp-bmenu-filter-alist-by-regexp in timer - pass no regexp arg. +;; Added: bookmarkp-some, *-bmenu-filter-(file-name|tags)-incrementally, +;; *-bmenu-filter-alist-by-(file-name|tags)-regexp, +;; *-regexp-filtered-(file-name|tags)-alist-only. +;; Renamed: *-bmenu-filter-incrementally to *-bmenu-filter-bookmark-name-incrementally, +;; *-bmenu-filter-alist-by-regexp to *-bmenu-filter-alist-by-bookmark-name-regexp, +;; *-regexp-filtered-alist-only to *-regexp-filtered-bookmark-name-alist-only. +;; Bound these commands to P B, P F, and P T. Updated bookmark-bmenu-mode doc string. +;; 2009/10/18 dadams +;; Added: *-bmenu-filter-(incrementally|delay|prompt|pattern|timer|alist-by-regexp), +;; *-bmenu-read-filter-input, *-regexp-filtered-alist-only, +;; *-bmenu-cancel-incremental-filtering. +;; *-bmenu-execute-deletions: Don't update menu list if this is a no-op. +;; Updated Commentary. +;; Thx to Thierry Volpiatto. +;; Added: *-marked-cp, *-bmenu-sort-marked-before-unmarked. Bound to s >. +;; *-define-sort-command: Use copy-sequence for default value. +;; 2009/10/17 dadams +;; Added: *-read-tags-completing, *-set-union, *-tag-history, *-describe-bookmark, +;; *-bmenu-describe-this-bookmark. Bound *-bmenu-describe-this-bookmark to C-h RET. +;; Use *-read-tags-completing instead of *-read-tags. +;; *-sort-orders-for-cycling-alist: Use copy-sequence. +;; *-bmenu-change-sort-order: Use member, not memq. +;; *-get-bookmark: Handle case of non-string, non-cons. Document NOERROR in doc string. +;; *-bmenu-execute-deletions: Fix so marks aren't removed if when delete. Thx to Thierry. +;; Convert recorded time to an Emacs time spec: +;; *-make-record-default, -add-or-update-time: Use current-time, not bookmark-float-time. +;; *-get-visit-time: Convert a deprecated time entry to an Emacs time spec. +;; *-bookmark-last-access-cp: Convert recorded time to a number for comparison. +;; Added: *-bmenu-show-filenames (redef of vanilla: put props on whole line, fit frame). +;; Removed: old-bookmark-insert-location. +;; *-insert-location: Do not call original. Redefined: do not add text properties. +;; *-bmenu-list, *-bmenu-hide-filenames: Put properties on line up to max width. +;; *-bmenu-goto-bookmark-named: Allow trailing whitespace, since we use the whole line now. +;; *-bmenu-list: Use pop-to-buffer, not switch-to-buffer. Use do-list, not mapcar. +;; *-bmenu-hide-filenames: fit-frame-if-one-window. +;; *-bmenu-propertize-item: Better help-echo text. +;; Updated bookmark-alist doc string to mention visits, time, and tags entries. +;; 2009/10/16 dadams +;; Added tags feature. +;; Added: *-(get|read)-tags, *-has-tag-p, *-remove(-all)-tags(-from-all), +;; *-bmenu-remove-tags-from-marked, *-add-tags(-to-marked), *-rename-tag, +;; *-bmenu-(un)mark-bookmarks-tagged-(all|none|some|not-all), +;; *-bmenu-mark/unmark-bookmarks-tagged-(all/none|some/not-all). +;; Bound to prefix key T. +;; *-bmenu-mode: Updated doc string. +;; Added: bookmarkp-default-bookmark-name. Use as default instead of *-current-bookmark. +;; Renamed: *-maybe-save-bookmark to *-maybe-save-bookmarks. +;; Menu-list commands: Raise an error if command is used outside the menu list. +;; 2009/10/15 dadams +;; Added: *-bmenu-(search|query-replace)-marked-bookmarks-regexp. Bound to M-a, M-q. +;; Renamed: *-non-marked-bookmarks-only to *-unmarked-bookmarks-only, +;; *-bookmark-marked-alist to *-bmenu-marked-bookmarks. +;; *-increment-visits, *-add-or-update-time: +;; Set *-bmenu-called-from-inside-p to t, so we don't remove marks. +;; Redefined *-bmenu-bookmark to get name from *-latest-sorted-alist. Thx to Thierry V. +;; *-bmenu-surreptitiously-rebuild-list, *-bmenu-list: +;; Removed optional arg DONT-TOGGLE-FILENAMES-P. +;; *-bmenu-execute-deletions, *-bmenu-toggle-show-only-(un)marked, *-bmenu-(un)mark-all, +;; *-bmenu-regexp-mark, *-bmenu-toggle-marks: +;; Do not bother with *-bmenu-toggle-filenames and rebuilding the menu list. +;; 2009/10/14 dadams +;; Added: *-bmenu-delete (redefinition), *-isearch-bookmarks, +;; *-bmenu-isearch(-marked)-bookmarks(-regexp), *-isearch-next-bookmark-buffer. +;; Bound multi-isearch commands to M-s a C(-M)-s. +;; 2009/10/13 dadams +;; Added: *-make-dired-record, *-jump-dired, *-dired-bookmark-p, *-dired-alist-only, +;; *-bmenu-show-only-dired. Bound *-bmenu-show-only-dired to M-d. +;; bookmarkp-file-bookmark-p: Include bookmarks that have the Dired handler. +;; Moved *-sort-orders-for-cycling-alist defcustoms after *-define-sort-command calls. +;; Call bookmarkp-msg-about-sort-order only when interactive. +;; *-add-or-update-time, *-increment-visits: Do not save each time we access a bookmark. +;; Updated doc string of bookmark-alist and Commentary. +;; 2009/10/09 dadams +;; Added: bookmarkp-bmenu-delete-marked. Bound it to D. +;; bookmarkp-sort-orders-for-cycling-alist. +;; Renamed: bookmarkp-sort-functions-alist to bookmarkp-sort-orders-alist, +;; bookmarkp-sort-function to bookmarkp-sort-comparer. +;; bookmark-bmenu-execute-deletions: Added optional arg, for *-bmenu-delete-marked. +;; *-sort-function: Changed default value to sorting by bookmark type (`s k'). +;; *-bmenu-change-sort-order: Use *-sort-orders-for-cycling-alist, not all sort orders. +;; Updated Commentary and doc string (bookmark-bmenu-mode). +;; 2009/10/08 dadams +;; Added: *-bmenu-sort-by-(w3m-url|gnus-thread), *-(gnus|w3m)-cp, *-cp-not, +;; *-local-file-(accessed|updated)-more-recently-cp, *-bmenu-sort-by-bookmark-type. +;; Renamed: *-bmenu-sort-by(-last)-file-(size|type|access|update) to +;; *-bmenu-sort-by(-last)-local-file-(size|typeaccess|update), +;; *-file-visited-more-recently-cp to *-local-file-accessed-more-recently-cp, +;; *-file-(size|type)-cp to *-local-file-(size|type)-cp. +;; Removed: *-file-(device|gid(-chg)|inode|last-(access|update|status-change)|links|modes +;; |uid)-cp. +;; Bound *-bmenu-sort-by-bookmark-type to `s k'. +;; *-define-file-sort-predicate: Use *-file-bookmark-p, not *-local-file-bookmark-p. +;; *-msg-about-sort-order: Added optional arg PREFIX-ARG. Use in: *-show-(all|only-*). +;; 2009/10/07 dadams +;; Renamed: *-bmenu-sort-by-last-visit-time to *-bmenu-sort-by-last-bookmark-access, +;; *-bmenu-sort-by-visit-frequency to *-bmenu-sort-by-bookmark-visit-frequency, +;; *-visited-more-recently-cp to *-bookmark-last-access-cp. +;; 2009/10/06 dadams +;; Added: bookmarkp-msg-about-sort-order. +;; bookmark-completing-read: Simple sort when use menu-bar menu. +;; 2009/10/05 dadams +;; Added: *-make-plain-predicate, *-reverse-multi-sort-order, *-multi-sort, +;; *-define-file-sort-predicate, *-bmenu-sort-by-file-*, *-file-attribute-*-cp, +;; and aliases *-file-*-cp, *-current-sort-order. +;; Redefined sorting to allow multi-predicates: +;; Redefined: *-sort-function, *-sort-and-remove-dups, *-define-sort-command, +;; *-sort-functions-alist. +;; Bound keys with `s f' prefix to file-sorting commands +;; *-current-sort-order: Use rassoc instead of rassq now. +;; Swap keys s and S. S is now bookmark-bmenu-save. s is not the sorting prefix key. +;; bookmark-bmenu-mode: Mention S key explicitly here (even though it is also +;; mentioned in the vanilla part of the doc string). +;; 2009/10/04 dadams +;; *-bmenu-change-sort-order-repeat: Require repeat.el. +;; Renamed: bookmarkp-current-sec-time to bookmarkp-float-time. +;; *-float-time: Added arg, so it's the same as float-time (for Emacs 20). +;; Bind *-reverse-sort-order to `S R'. +;; *-remote-file-bookmark-p: Removed extra rem-file in last and. +;; *-non-file-bookmark-p: Ensure it's not a remote file, before calling file-exists-p. +;; 2009/10/03 dadams +;; Added: bookmarkp-file-remote-p, bookmarkp-buffer (face). +;; bookmarkp-non-file (face): Changed to gray. +;; *-default-handler, *-bmenu-propertize-item, *-(info|file)-bookmark-p: +;; Support Emacs 20-21 Info-node bookmarks. +;; bookmarkp-bmenu-propertize-item: Use different face for existing buffers. +;; Use bookmarkp-non-file-filename. +;; bookmarkp-non-file-bookmark-p: Include buffer bookmarks for nonexistent buffers. +;; bookmarkp-remote-file-bookmark-p: Use bookmarkp-file-remote-p. +;; bookmark-handle-bookmark: +;; Redefine for all Emacs versions. Handle buffer (non-file) bookmarks. +;; Reordered some function definitions. +;; 2009/10/02 dadams +;; Added: bookmarkp-bmenu-goto-bookmark-named, bookmarkp-latest-sorted-alist. +;; *-sort-and-remove-dups: Set *-latest-sorted-alist (not used yet). +;; *-define-sort-command, *-bmenu-change-sort-order, *-reverse-sort-order: +;; Bind *-bmenu-called-from-inside-p to t, to prevent losing marks. +;; Restore cursor position to same bookmark after sorting - use *-goto-bookmark-named. +;; *-bmenu-surreptitiously-rebuild-list, *-bmenu-list: Added arg DONT-TOGGLE-FILENAMES-P. +;; *-bmenu-execute-deletions, *-bmenu-toggle-show-only-(un)marked: +;; Call *-surreptitiously-* with arg DONT-TOGGLE-FILENAMES-P. +;; *-bmenu-hide-filenames: Simplify - don't get to position by searching backward. +;; *-handle-region-default: Use forward-line, not goto-line. +;; Thx to Thierry V. +;; 2009/10/01 dadams +;; Added: bookmarkp-some-unmarked-p. +;; Renamed: *-bmenu-toggle-show-only- to *-bmenu-show-only-, +;; *-bmenu-called-from-inside-flag to *-bmenu-called-from-inside-p. +;; bookmarkp-some-marked-p: Do not test bookmarkp-bookmark-marked-alist. +;; Arg must be required (explicit). Changed calls accordingly. +;; bookmark-bmenu-mode: Cleaned up doc string. +;; bookmark-bmenu-((un)mark|rename|edit-*|toggle-marks|surreptitiously-rebuild-list), +;; bookmarkp-root-or-sudo-logged-p, bookmarkp-jump-w3m-(new-session|only-one-tab), +;; bookmarkp-some-marked-p: +;; Inline let vars used only once. +;; bookmarkp-bmenu-toggle-show-only-marked: +;; Test bookmarkp-some-unmarked-p, not bookmarkp-some-marked-p, +;; and include *-before-hide-unmarked in the test. +;; bookmarkp-bmenu(-toggle)-show-only-*: Display status message. +;; bookmarkp-bmenu-toggle-show-only-(un)marked: Fit frame. +;; bookmark-prop-set: Fixed, so it handles old bookmark format also. +;; 2009/10/01 Thierry Volpiatto +;; Removed: bookmarkp-bmenu-restore-marks. +;; bookmark-bmenu-list: +;; Do the mark restoration in line, at the same time as the annotation * restoration. +;; Simplify use of START and END. +;; 2009/09/30 dadams +;; bookmarkp-bmenu-regexp-mark: Remove binding of bookmark-alist. +;; bookmark-bmenu-(un)mark, bookmarkp-bmenu-edit-bookmark (remove first call only), +;; bookmark-bmenu-other-window, bookmark-bmenu-rename, bookmarkp-bmenu-restore-marks: +;; Remove bookmark-bmenu-check-position (done by bookmark-bmenu-bookmark anyway). +;; bookmark-insert-location: Fix interactive spec for Emacs < 22. +;; bookmark-location: Return "" instead of raising error, if no location found. +;; bookmarkp-current-sec-time: Move the let: do not call current-time unless we need to. +;; bookmarkp-bmenu-unmark-all: forward-line only 1, not 2. Thx to Thierry. +;; bookmark-bmenu-mode: Updated doc string - bindings and mention options. +;; bookmarkp-bmenu-propertize-item: For buffer, check also against " - no file -". +;; 2009/09/29 dadams +;; bookmark-bmenu-unmark: Use delete, not remove. +;; Removed: bookmark-bmenu-check-position, bookmarkp-maybe-sort. +;; Added: bookmarkp-sort-and-remove-dups, bookmarkp-remove-assoc-dups, +;; bookmarkp-face-prop, bookmarkp-bad-bookmark, bookmark-menu-heading (Emacs 20,21), +;; bookmark-bmenu-bookmark (redefinition). +;; *-bmenu-toggle-show-only-*: Do not call-interactively. +;; bookmarkp-bmenu-(un)mark-all: +;; Handle bookmark-bmenu-toggle-filenames (wrapper). +;; Remove bookmark-bmenu-check-position - just ensure within menu list. +;; bookmarkp-bmenu-mark-all: Move save-excursion so it applies to all movements. +;; Message stating number marked. +;; bookmarkp-bmenu-unmark-all: Use with-current-buffer ensure in menu list. +;; Use bookmark-bmenu-unmark. +;; Fixed U bindings for bookmarkp-bmenu-unmark-all. +;; bookmarkp-bmenu-regexp-mark: +;; Remove bookmark-bmenu-check-position - just ensure in menu list. +;; bookmarkp-bmenu-toggle-marks: Use forward-line 2, to ensure in menu list. +;; Message stating number marked. +;; bookmark-bmenu-list, bookmarkp-bmenu-propertize-item: Use bookmarkp-face-prop. +;; bookmark-bmenu-list: Don't start applying the faces until column 2. +;; Removed key bindings in bookmark-map for *-toggle-show-only-*. +;; Redefined faces, esp. for a light background. +;; Use font-lock-face or face property, depending on Emacs version. +;; +;; 2009-06-09 to 2009-09-27 Thierry Volpiatto and dadams +;; New features, as follows. +;; See also the change log at +;; http://mercurial.intuxication.org/hg/bookmark-icicle-region/. +;; 2090-09-27 Rewrote sorting and unmarking code. (+ Updates to doc, names.) +;; Unmarking is now like Dired & query-replace. +;; Sorting is via one sort function; sort predicates do all the sorting. +;; Can now cycle sort orders with S S S... +;; Sort cmds now cycle among normal, reverse, off. +;; Add: *-define-sort-command (macro), *-assoc-delete-all, *-upcase, +;; *-get-visits-count, *-get-visit-time, *-sort-functions-alist. +;; Remove docstring from defalias (for Emacs 20). +;; 2009-09-26 Fix *-bmenu-mode doc (defadvice). +;; 2009-09-25 *-bmenu-edit, *-bmenu-sort-1: Fix bmk retrieval code. +;; Redefine *-bmenu-unmark. Add: *-bmenu-toggle-marks. +;; Bind *-bmenu-unmark-all-bookmarks to M-DEL. Reorder code. +;; Rename: *-bmenu-unmark-all-(bookmarks|(delete|mark)-flag)', +;; *-bmenu-unmark-all-bookmarks-1. +;; Change sort predicates in defalias. Rename bmk entry visit to visits. +;; Remove: *-bmenu-show-number-of-visit. +;; 2009-09-22 Rewrote sorting code. Renamed unmarking fns. +;; 2009-09-21 Rename mark/unmark cmds to have -bmenu. +;; Add: *-bmenu-called-from-inside-flag - set it in (un)hide marks fns. +;; 2009-09-20 *-write-file: Remove text properties before saving. +;; Remove all marks only in current display. +;; 2009-09-19 *-current-sec-time: Protect with fboundp for Emacs 20. +;; *-bmenu-sort-1: Add msg showing sort method. +;; Change key S-A to S-S (A is annotations). +;; 2009-09-18 Improve sorting by visit frequency. Always increment when jump. +;; Fix increment visit fn. Allow sorting by last visited. +;; When visit values are equal, sort with string-lessp. +;; Add TIME bookmark-alist entry. *-make-record-default: Add time entry. +;; Fix: bad parens, errors in sorting predicate. Rename fns. +;; Use single fn to sort using diff methods. +;; Add: *-bmenu-refresh-alist (bind to g). +;; 2009-09-16 Add: *-toggle-sorting-by-most-visited, *-reset-visit-flag, +;; *-bmenu-show-number-of-visit. +;; Redefine *-prop-set. Improve *-toggle-sorting-by-most-visited. +;; Add auto-doc to header. *-bmenu-mode: Add missing key. +;; Update menu-list after jumping. +;; Increment save counter when jump with visit flag. +;; 2009-09-15 Record number of visits. Added sorting by most visits. +;; 2009-09-14 Add doc string. Update defadvice doc string wrt keys. +;; 2009-09-12 Add: fns to mark all, unmark D or > or all, *-bmenu-reset-alist. +;; Fix keymap (Emacs 20). *-unmark-all-bookmarks1: Move the save-excursion. +;; 2009-09-11 Add: *-bmenu-check-position (redef to improve performance), +;; *-unmark-all-bookmarks, *-current-list-have-marked-p, +;; *-bookmark-marked-p, *-(non-)marked-bookmarks-only. +;; *-bmenu-hide-unmarked: Add toggling. Restore lost fn. +;; Reorder code. Bind cmds in *-bmenu-mode-map. +;; *-bmenu-hide-marked: Do not hide if no marked in current filter. +;; Improve: *-bmenu-hide(-not)-marked-bookmark, (un)hide marked fns. +;; 2009-09-10 Fix *--restore-all-mark, *-bmenu-regexp-mark. +;; *-bmenu-list: Add *-restore-all-mark. +;; *-bmenu-mark: Push marked bmk to marked list. +;; Add: bookmarkp-bookmark-marked-list, *-bmenu-quit. +;; 2009-09-09 *-maybe-sort-alist: Use copy-sequence. +;; So remove fixes for *-rename, *-edit-bookmark. +;; *-yank, *-rename', *-set: Fix yanking. +;; Remove non-file bmks from file-only list. +;; Add: *-bmenu-list-only-non-file-bookmarks, *-maybe-message (Emacs 20), +;; *-bmenu-mark-bookmark-matching-regexp, *-bmenu-hide-marked-bookmark, +;; *-bmenu-hide-not-marked-bookmark, *-bmenu-mark (redefinition). +;; *-write-file: Improve performance. +;; *-non-file-alist-only: Remove unused def. +;; Fix: hide marked/unmarked with toggle-filenames, keymap for Emacs 20. +;; Improve comments, doc strings. +;; *-bmenu-mark-bookmark-matching-regexp: Fix while loop. +;; 2009-09-08 bookmark-store: Remove duplicate setq of *-current-bookmark. +;; 2009-09-07 Reorganize (reorder), add comments, improve doc strings. +;; Change binding of *-bmenu-relocate from R to M-r. +;; 2009-09-06 bookmark-rename: Redefine with new arg BATCH. +;; *-bmenu-rename: Go to new pos, not old. +;; *-edit-bookmark, bookmark-rename: Fix display update for Emacs 20. +;; 2009-09-05 Add: *-edit-bookmark, *-bmenu-edit-bookmark, *-maybe-save-bookmark. +;; 2009-09-04 Require cl. Allow RET in Emacs 20. Add doc string. +;; *-fix-bookmark-alist-and-save: +;; 2009-09-03 Fix *-fix-bookmark-alist-and-save: +;; Use error, not message. Change value for setcdr. +;; Do not use push with non-var (cl). +;; bookmark-delete: +;; Redefine, to fix vanilla bug: increment count even when BATCHP is non-nil. +;; *-non-file-name: Change to - no file -. *-bmenu-list: Add arg FILTER-ON. +;; *-bmenu-execute-deletions: Use delete, not remove. +;; Add: *-replace-regexp-in-string. +;; bookmark-set: Fix *-yank-point for region case. Fix bad parens. +;; 2009-09-02 Add: *-non-file-filename. *-fix-bookmark-alist-and-save: Fix msg. +;; Require cl (gensym). *-at-bol/eol' -> line-*-position (for Emacs 20). +;; Redefine *-bmenu-execute-deletions, +;; *-bmenu-surreptitiously-rebuild-list. +;; Update current filtered display - do not reload & display all bmks. +;; Add redefinitions of *-bmenu-rename', *-yank-word to fix vanilla bugs: +;; *-bmenu-rename: Do not call *-bmenu-list twice. +;; *-yank-word: Do not insert whitespace. +;; Rename *-last-bookmark-alist-in-use to *-latest-bookmark-alist. +;; 2009-09-01 Fix: Loading of new doc for bookmark-alist (add vacuous defvar). +;; *-bmenu-(list|hide-filenames): start -> end, end -> start. +;; Removed extraneous quote mark that caused problems. +;; Save only if condition-case exits OK. +;; 2009-08-31 Fixes: Test for non-file bmk. Filename for Gnus bmks. +;; Compatibility of bookmark-alist with vanilla Emacs. +;; Require info.el and ffap.el when needed. +;; Add: *-line-number-at-pos (for Emacs 20), +;; *-bmenu-other-window (redefinition). +;; Rename *-propertize-bookmark-list to *-propertize-bmenu-item. +;; 2009-08-30 Fix: Increment *-alist-modification-count when relocate region, +;; and maybe save. +;; Move code adding properties to bookmarks out of *-bmenu-list. +;; mapc -> mapcar. *-bmenu-hide-filenames: Redefine. +;; 2009-08-29 Remove refresh code. +;; 2009-08-27 Added: *-local-directory-bookmark-p, *-local-file-alist-only, +;; *-non-file-alist-only. +;; *-file-bookmark-p: Redefined to exclude bmks with handlers. +;; Renamed fns and faces. +;; 2009-08-25 Fit frame after display menu list. +;; Refresh list when toggle filename visibility. +;; 2009-08-24 Fix: *-bmenu-list for remote files, bookmark-set, *-remote-file-bookmark-p. +;; Ensure arg to file-remote-p is not nil. +;; Recenter region only if it is visible. +;; 2009-08-23 Remove old *-location. *-bmenu-list: Add isw3m. +;; bookmark-set: +;; Redefine for older Emacs. Use a default prompt for gnus, w3m. +;; Use *-name-length-max for title when region is active. +;; Ensure bookmark is on one line. +;; 2009-08-22 Try to handle tramp ftp files. +;; Do not fail if bookmark has empty filename entry. +;; Show region end pos using exchange-point-and-mark. +;; 2009-08-21 Remove all cl stuff (list*, loop, etc.). Add *-remove-if(-not). +;; Remove compile-time require of cl. +;; Add predicates *-(region|gnus|w3m|info|(remote-|local-)file)-bookmark-p. +;; Redefine alist-only functions to optimize and use new preds. +;; 2009-08-20 *--jump-via: Fix to show relocated region before ask whether to save. +;; *-relocate-region: Fix ar-str. Rename a var. Add: *-region-activated-p. +;; Revert chgs. +;; 2009-08-19 Update/fix commentary: bookmark-alist, linkd. +;; *-default-handler, *-handle-region-default: +;; Get bmk record from name only once. +;; *-save-new-region-location: Move t inside progn. +;; 2009-08-16 Use prefix bookmarkp where appropriate. +;; 2009-08-15 Improve comments, doc strings. Rename fns, vars. +;; Add :group with prefix bookmarkp. +;; 2009-08-09 Fix doc strings. +;; 2009-08-08 bookmark-set: Update doc string. Show keys in C-h m. +;; 2009-08-07 *-jump: Fix to jump in same window (thx to Henry Atting). +;; *-at-bol/eol' -> line-*-position. +;; 2009-08-01 bookmark-store: Fix for Emacs 20. +;; 2009-07-27 Ensure we start on an empty w3m buffer. Add: *-w3m-allow-multi-tabs. +;; 2009-07-24 *-bmenu-mode-map: Define some new keys. +;; 2009-07-23 *-bmenu-list: Add path to file in help-echo. +;; 2009-07-19 Fix title underline. Highlight bookmark if root logged with tramp. +;; Add face for sudo. +;; 2009-07-18 Add: filter functions, option for bookmark-bmenu-list. +;; Remove toggle region. +;; *-bmenu-list-only-files-entries: Add prefix arg to show remote. +;; 2009-07-14 Add a forgotten test. +;; 2009-07-13 Fix errors. Give pos in msg even if no search. +;; *-from-bob/eob: Fixed like old strict. +;; Remove *-relocate-region-(method|from-limits). +;; Remove unused code in record fns. Add: *-relocate-region-function. +;; 2009-07-12 Do not pass args to relocation routines. Remove use of flet. +;; Use skip-chars-*ward. Use forward-line, not beginning-of-line. +;; Remove save-excursion around message. Correct typo f(ree var BMK). +;; 2009-07-11 Fix *-relocate-region-strict. Rename fns, adjust defcustom. +;; Save relocated region after pushing mark. Add comments. +;; 2009-07-10 New retrieve fn. Add looking-* fns. +;; 2009-07-08 Simplify record fns. Add doc strings. Add: *-save-relocated-position. +;; Fix: updating when relocate (wrt new record fns), string closing, +;; free vars, parens, names. +;; 2009-07-06 Fix: *-bmenu-list wrt windows, Info colors. +;; 2009-07-04 Rename fns to record, vars, args of retrieve fns. Big changes, fixes. +;; 2009-07-01 Fix comments. *-retrieve-region-strict: improve when out of context. +;; 2009-06-30 Fix: free vars, *-retrieve-region, provide (name). +;; 2009-06-29 Fix: w3m handler, file name for non-file, *-simple-retrieve-position. +;; Add: *-retrieve-region-strict. +;; 2009-06-28 Add: *-retrieve-region-method-is, *-retrieve-region-lax, +;; fns to retrieve regions. +;; Use buffer again, not buffer-name. +;; 2009-06-27 Fix wrong-type error no such file. Renamed faces. Add: *-prop-set. +;; Load gnus at compile time. Protect tramp-file-name-regexp with boundp. +;; 2009-06-25 Fixes for older Emacs compatibility. +;; 2009-06-24 Improve *-default-handler. +;; Add: *-always-save-relocated-position, *-prop-get. +;; 2009-06-23 Use search-regexp, not re-search-regexp. Add Gnus bmks. Add doc. +;; Fix *-bmenu-list. +;; 2009-06-21 Fix: *-default-handler for Info. Improve doc strings, commentary. +;; Fixes to be compatible with Emacs 20-22. +;; Use defcustom for *-list-only-regions-flag. +;; *jump: Put prefix arg in interactive spec. Use buffer-name, not buffer. +;; Remove require of Tramp and inline Tramp fns. +;; Remove tests for display-(color|mouse)-p. +;; w3m-bookmark-(jump|make-record): require w3m. +;; 2009-06-20 Update context strings when relocate. +;; Fix: bookmark-get-*: search from point-min. +;; 2009-06-19 Fix: *-make-record-default, *-toggle-use-only-regions, *-default-handler, +;; bookmarking Dired. +;; Handle 4 positions in *-default-handler. +;; 2009-06-17 Fix: case where some bookmarked text was removed, *-use-region. +;; 2009-06-15 Fix *-region-alist-only, *-get-buffername, *-location, +;; non-file (buffer) bookmarks. +;; Support w3m similar to Info. +;; 2009-06-14 Fix bookmark+version, region relocation. Info support. Error handling. +;; 2009-06-13 Fix: *-list-only-regions, *-region-handler, *-make-record, keymap, faces. +;; Put region & info handling in *-default-handler, not separate handlers. +;; Merge *-make-record-region to *-make-record-default. +;; *-jump now negates *-use-region if prefix arg. Raise error if bad bmk. +;; 2009-06-12 Add: *-get-endposition, *-region-alist-only-names. +;; Add filter to show only region bookmarks. +;; Faces for menu list. Change region color. +;; 2009-06-11 Add: *-region-search-size, *-get-buffername, *-use-region. +;; Redefine *-handle-bookmark, *-jump, to fit bookmark-use-region. +;; Add condtions to bookmark-make-record. Support w3m. Support t command. +;; 2009-06-10 Fix search regexp. Fix region in Info. Save bookmark if region moves. +;; 2009-06-09 Added: bookmark-make-record(-region), bookmark-region-handler. +;; Relocation. +;; 2009/05/25 dadams +;; Added redefinition of bookmark-get-bookmark-record. +;; 2008/10/16 dadams +;; bookmark-jump-other-window: Don't define it for Emacs 23+ (not needed). +;; 2008/04/04 dadams +;; bookmark-jump-other-window: Updated wrt Emacs 22.2. +;; 2007/10/07 dadams +;; Added: bookmark-completing-read, bookmark-delete, bookmark-insert(-location), +;; bookmark-jump, bookmark-relocate, bookmark-rename. +;; bookmark-jump-other-window: Use new bookmark-completing-read. +;; 2007/07/13 dadams +;; Replaced Emacs version tests to reflect Emacs 22 release. +;; 2006/03/08 dadams +;; bookmark-jump-other-window: Handle nil arg. +;; 2005/05/17 dadams +;; Updated to work with Emacs 22.x. +;; 2004/11/20 dadams +;; Refined to deal with Emacs 21 < 21.3.50 (soon to be 22.x) +;; 2004/10/26 dadams +;; Different menu-bar command, depending on Emacs version. +;; 2004/09/21 dadams +;; Only define bookmark-menu-jump-other-window if < Emacs 22. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;; You need not load this file. It contains only documentation. + +(provide 'bookmark+-chg) ; Not used. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-chg.el ends here diff --git a/lisp/bookmark+-doc.el b/lisp/bookmark+-doc.el new file mode 100644 index 00000000..603ed104 --- /dev/null +++ b/lisp/bookmark+-doc.el @@ -0,0 +1,4289 @@ +;;; bookmark+-doc.el - Documentation for package Bookmark+. +;; +;; Filename: bookmark+-doc.el +;; Description: Documentation for package Bookmark+ +;; Author: Drew Adams +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2000-2022, Drew Adams, all rights reserved. +;; Created: Fri Sep 15 07:58:41 2000 +;; Last-Updated: Fri Jan 14 12:46:47 2022 (-0800) +;; By: dradams +;; Update #: 15385 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-doc.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+, placeholders, annotations, search, +;; info, url, eww, w3m, gnus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Documentation for the Bookmark+ package, which provides +;; extensions to standard library `bookmark.el'. +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) library +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit.el' - (optional) code for highlighting bookmarks +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (bmenu) +;; `bookmark+-1.el' - other required code (non-bmenu) +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc.el' - documentation (comment-only - this file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; The documentation includes how to byte-compile and install +;; Bookmark+. It is also available in these ways: +;; +;; 1. From the bookmark list (`C-x x e' or `C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if put you this +;; library, `bookmark+-doc.el', in your `load-path'.) +;; +;; More Bookmark+ description below. +;; +;; To report Bookmark+ bugs: `M-x customize-group bookmark-plus' +;; and then follow (e.g. click) the link `Send Bug Report', which +;; helps you prepare an email to me. +;; +;; +;; ****** NOTE ****** +;; +;; On 2010-06-18, I changed the prefix used by package Bookmark+ +;; from `bookmarkp-' to `bmkp-'. THIS IS AN INCOMPATIBLE CHANGE. +;; I apologize for the inconvenience, but the new prefix is +;; preferable for a number of reasons, including easier +;; distinction from standard `bookmark.el' names. +;; +;; This change means that YOU MUST MANUALLY REPLACE ALL +;; OCCURRENCES of `bookmarkp-' by `bmkp-' in the following +;; places, if you used Bookmark+ prior to this change: +;; +;; 1. In your init file (`~/.emacs') or your `custom-file', if +;; you have one. This is needed if you customized any +;; Bookmark+ features. +;; +;; 2. In your default bookmark file, `bookmark-default-file' +;; (`~/.emacs.bmk'), and in any other bookmark files you might +;; have. +;; +;; 3. In your `*Bookmark List*' state file, +;; `bmkp-bmenu-state-file' (`~/.emacs-bmk-bmenu-state.el'). +;; +;; 4. In your `*Bookmark List*' commands file, +;; `bmkp-bmenu-commands-file' (`~/.emacs-bmk-bmenu-commands.el'), +;; if you have one. +;; +;; You can do this editing in a virgin Emacs session (`emacs +;; -Q'), that is, without loading Bookmark+. +;; +;; Alternatively, you can do this editing in an Emacs session +;; where Bookmark+ has been loaded, but in that case you must +;; TURN OFF AUTOMATIC SAVING of both your default bookmark file +;; and your `*Bookmark List*' state file. Otherwise, when you +;; quit Emacs your manually edits will be overwritten. +;; +;; To turn off this automatic saving, you can use `M-~' and +;; `C-M-~' in buffer `*Bookmark List*' (commands +;; `bmkp-toggle-saving-bookmark-file' and +;; `bmkp-toggle-saving-menu-list-state' - they are also in the +;; `Bookmark+' menu). +;; +;; Again, sorry for this inconvenience. + +;;(@> "Index") +;; +;; Index +;; ----- +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "Documentation") +;; (@> "Installing Bookmark+") +;; (@> "Bookmark+ Load Order and Option `bookmark-default-file'") +;; (@> "Bookmark+ Features") +;; (@> "Bookmark Basics") +;; (@> "Different Types of Jump Commands") +;; (@> "Bookmark Annotations") +;; (@> "Bookmark Tags") +;; (@> "Bookmark Tags Can Have Values") +;; (@> "Hierarchical Structures of Bookmarks?") +;; (@> "Function, Sequence, Variable-List,... Bookmarks") +;; (@> "Little Persistent Named Nothings") +;; (@> "Editing Bookmarks") +;; (@> "Bookmark Records: What A Bookmark Looks Like") +;; (@> "Bookmark-List Views - Saving and Restoring State") +;; (@> "Quitting Saves the Bookmark-List State") +;; (@> "State-Restoring Commands and Bookmarks") +;; (@> "Bookmarking without Visiting the Target") +;; (@> "Bookmarking a File or a URL") +;; (@> "Bookmarking the Marked Files in Dired") +;; (@> "Bookmarking Compilation, Grep, and Occur Hits") +;; (@> "Bookmarking Files That You Cannot Visit with Emacs") +;; (@> "Opening Bookmarks Using Windows File Associations") +;; (@> "Autofile Bookmarks") +;; (@> "A Type-Aware `find-file'") +;; (@> "Tagging Files") +;; (@> "Using Multiple Bookmark Files") +;; (@> "Bookmark-File Bookmarks") +;; (@> "The Bookmark List Display") +;; (@> "Jumping To Bookmarks from the Bookmark List Display") +;; (@> "Tag Commands and Keys") +;; (@> "Tags: Sets of Bookmarks") +;; (@> "Open Dired for the Marked File Bookmarks") +;; (@> "Marking and Unmarking Bookmarks") +;; (@> "Filtering Bookmarks (Hiding and Showing)") +;; (@> "Only Visible Bookmarks Are Affected") +;; (@> "Omitting Bookmarks from Display") +;; (@> "Sorting Bookmarks") +;; (@> "Bookmarks for Specific Files or Buffers") +;; (@> "Cycling, Navigation List") +;; (@> "The Bookmark Navigation List") +;; (@> "Cycling the Navigation List") +;; (@> "Cycling Dynamic Sets of Bookmarks") +;; (@> "Cycling in the Current File/Buffer") +;; (@> "Autonamed Bookmarks - Easy Come Easy Go") +;; (@> "Temporary Bookmarks") +;; (@> "Temporary Bookmarking Mode") +;; (@> "Making Bookmarks Temporary") +;; (@> "Automatic Bookmarking") +;; (@> "Automatic Bookmarking Using a Hook") +;; (@> "Automatic Idle-Period Bookmarking") +;; (@> "Automatic Info Bookmarking") +;; (@> "Highlighting Bookmark Locations") +;; (@> "Defining How to Highlight") +;; (@> "Highlighting On Demand") +;; (@> "Highlighting Automatically") +;; (@> "Using Highlighted Bookmarks") +;; (@> "Bookmark Links") +;; (@> "Org Mode Links that Jump To Bookmarks") +;; (@> "Bookmark Menus") +;; (@> "Use Bookmark+ with Icicles") +;; (@> "Bookmark Compatibility with Vanilla Emacs (`bookmark.el')") +;; (@> "New Bookmark Structure") + +;;(@* "Documentation") +;; +;; Documentation +;; ------------- +;; +;;(@* "Installing Bookmark+") +;; ** Installing Bookmark+ ** +;; +;; The main Bookmark+ library is `bookmark+.el'. The other required +;; libraries are `bookmark+-mac.el', `bookmark+-bmu.el', +;; `bookmark+-1.el', and `bookmark+-key.el'. If you want to be able +;; to highlight bookmarks then you will also need library +;; `bookmark+-lit.el'. I recommend that you byte-compile all of the +;; libraries, after loading the source files (in particular, load +;; `bookmark+-mac.el'). +;; +;; Put the directory of these libraries in your `load-path' and add +;; this to your init file (~/.emacs): +;; +;; (require 'bookmark+) +;; +;; That will load all of the Bookmark+ libraries. If you do not care +;; about bookmark highlighting then simply do not put +;; `bookmark+-lit.el' in your `load-path'. +;; +;; By default (see option `bmkp-crosshairs-flag'), when you visit a +;; bookmark that has no region it is highlighted temporarily using +;; crosshairs, for easy recognition. (This temporary highlighting is +;; independent of the highlighting provided by `bookmark+-lit.el'.) +;; +;; For this optional crosshairs feature you also need library +;; `crosshairs.el', which in turn requires libraries `col-highlight', +;; `hl-line', `hl-line+', and `vline'. Library `hl-line' comes with +;; vanilla Emacs. The others are available from the Emacs Wiki web +;; site: https://www.emacswiki.org/. You also need Emacs 22 or later +;; for this feature. +;; +;; +;;(@* "Bookmark+ Load Order and Option `bookmark-default-file'") +;; *** Bookmark+ Load Order and Option `bookmark-default-file' *** +;; +;; Standard option `bookmark-default-file' defines the default +;; location of your bookmark file. Bookmark+ does not change the +;; value. You can change the value, of course, either by customizing +;; it (recommended) or using Lisp code (including in your init file). +;; +;; However, the value of `bookmark-default-file' is used when you +;; load Bookmark+ to initialize some other variables, in particular +;; option `bmkp-last-as-first-bookmark-file' and internal variable +;; `bmkp-current-bookmark-file'. +;; +;; This means that if you modify `bookmark-default-file' in your init +;; file, and you want your new value to be take into account by +;; Bookmark+, then modify it before you load Bookmark+. +;; +;; Be aware also that another library that you load might, itself, +;; load Bookmark+, in which case you will for the same reason want to +;; load that library after you have modified `bookmark-default-file'. +;; An example of this is Icicles, which loads Bookmark+ if Bookmark+ +;; is in your `load-path'. +;; +;; In general, with Bookmark+ I recommend that you simply set option +;; `bookmark-default-file' once and for all at the outset, preferably +;; by customizing it. You can use `bmkp-switch-bookmark-file-create' +;; at any time to switch to a different bookmark file - it is bound +;; to `C-x x L'. You can also invoke it in your init file, provided +;; Bookmark+ has already been loaded. +;; +;; See Also: (@> "Using Multiple Bookmark Files") + +;;(@* "Bookmark+ Features") +;; ** Bookmark+ Features ** +;; +;; Here is an overview of some of the features that Bookmark+ +;; provides. Some of these are detailed in other sections, below. +;; +;; * Richer bookmarks. They record more. They are more accurate. +;; +;; - An optional bookmark annotation is user-supplied text that is +;; saved as part of the bookmark. You can use any text you +;; like, and you can use it for any purpose you like. In +;; Bookmark+, the mode for viewing and editing a bookmark +;; annotation is Org mode, by default. +;; +;; - In addition, Bookmark+ lets you optionally use a separate +;; file, URL, or bookmark to annotate any bookmark. Accessing +;; ("showing") such an external annotation visits its +;; destination. So for example, you can use bookmarks to one or +;; more Org files to annotate one or more bookmarks. The +;; annotation saved with the bookmark itself just specifies the +;; destination. See (@> "Bookmark Annotations"). +;; +;; - You can tag bookmarks, a la del.icio.us. In effect, tags +;; define bookmark sets. A bookmark can have any number of +;; tags, and multiple bookmarks can have the same tag. You can +;; sort, show/hide, or mark bookmarks based on their tags. +;; +;; - Bookmark+ tags can be more than just names. They can be +;; full-fledged user-defined attributes, with Emacs-Lisp objects +;; as their values. +;; +;; - You can have multiple bookmarks with the same name. This is +;; particularly useful for autofile bookmarks, which are +;; bookmarks that have the same name as their target files or +;; directories. They give you the effect of using files or +;; directories themselves as bookmarks. In particular, they let +;; you, in effect, tag files and directories. +;; See (@> "Autofile Bookmarks") and (@> "Tagging Files"). +;; +;; (In vanilla Emacs you can also, in theory, have multiple +;; bookmarks with the same name. But you cannot really use them +;; in any practical way. Vanilla Emacs cannot distinguish among +;; them: the most recent one shadows all others with the same +;; name.) +;; +;; - Bookmarks record the number of times you have visited them +;; and the time of the last visit. You can sort, show/hide, or +;; mark bookmarks based on this info. +;; +;; - You can combine bookmarks, to make composite, or sequence, +;; bookmarks. Invoking a sequence bookmark invokes each of its +;; component bookmarks in turn. A component bookmark can itself +;; be a sequence bookmark. +;; +;; - You can bookmark a region of text, not just a position. When +;; you jump to a bookmark that records a region, the region is +;; activated (see option `bmkp-use-region'). (Region activation +;; is not supported for Gnus bookmarks.) +;; +;; You can define your own region handler for bookmarks that +;; record regions. (This is in addition to being able to define +;; bookmark handlers.) Use option `bmkp-handle-region-function' +;; for this. As one example, command +;; `bmkp-region-jump-narrow-indirect-other-window' binds the +;; option to a function that narrows the targeted region in a +;; cloned indirect buffer. (You need library +;; `narrow-indirect.el' for this command.) +;; +;; - Bookmarks are relocated better than for vanilla Emacs when +;; the contextual text changes. +;; +;; * Additional ways to bookmark. +;; +;; - You can bookmark the file or URL named at point (or any other +;; file or URL), without first visiting it. +;; +;; - You can bookmark the targets of the hits in a compilation +;; buffer or an `occur' buffer, without first visiting them. +;; +;; - You can bookmark all of the marked files in Dired at once. +;; +;; * Additional types of bookmarks. +;; +;; Bookmark+ adds over 70 types of bookmark. (You can see what they +;; all are by invoking function `bmkp-types-alist'.) Here are the +;; main ones: +;; +;; - Autofile bookmarks. You can bookmark a file without visiting +;; it or naming the bookmark. The bookmark name is the same as +;; the file name (nondirectory part). You can have multiple +;; such bookmarks with the same name, to bookmark files with the +;; same name but in different directories. +;; +;; - Dired bookmarks. You can bookmark a Dired buffer, recording +;; and restoring its `ls' switches, which files are marked, +;; which subdirectories are inserted, and which (sub)directories +;; are hidden. +;; +;; - Dired-tree bookmarks. A set of Dired bookmarks that +;; represent a directory hierarchy and are opened together. +;; +;; - Bookmark-list bookmarks. You can bookmark the current state +;; of buffer `*Bookmark List*' - a list of bookmarks. Jumping +;; to such a bookmark restores the recorded sort order, +;; markings, filter, title, and omit list. +;; See (@> "Omitting Bookmarks from Display"). +;; +;; - Bookmark-file bookmarks. You can bookmark a bookmark file. +;; Jumping to such a bookmark loads the bookmarks in the file. +;; See (@> "Bookmark-File Bookmarks"). +;; +;; - Desktop bookmarks. You can bookmark the current Emacs +;; desktop, as defined by library `desktop.el' - use command +;; `bmkp-set-desktop-bookmark' (`C-x x K'). You can "jump" to a +;; desktop bookmark (that is, restore its saved desktop). A +;; desktop includes: +;; +;; - Some global variables. To exclude variables normally +;; saved, see option `bmkp-desktop-no-save-vars'. +;; - The current set of buffers and their associated files. +;; For each: its mode, point, mark, & some local variables. +;; +;; If option `bmkp-desktop-jump-save-before-flag' is non-`nil', +;; and if the current desktop was made current by jumping to a +;; bookmark, then it is saved before jumping to the next +;; desktop. If you want to save the last desktop jumped to when +;; you quit Emacs, then add `bmkp-desktop-save-as-last' to +;; `kill-emacs-hook'. +;; +;; - Gnus bookmarks. You can bookmark a Gnus article, a URL, a +;; PDF file (DocView), a UNIX manual page (from the output of +;; Emacs command `man' or `woman'), an image, or a piece of +;; music. +;; +;; - Non-file (buffer) bookmarks. You can bookmark a buffer that +;; is not associated with a file. +;; +;; - Function bookmarks. A bookmark can represent a Lisp +;; function, which is invoked when you "jump" to the bookmark. +;; +;; - Sequence (composite) bookmarks. A bookmark can represent a +;; sequence of other bookmarks. +;; +;; - Keyboard-macro bookmarks, bookmarks for sets of keyboard +;; macros, and sequence bookmarks that combine another bookmark +;; with a keyboard macro. +;; +;; - Lisp variable bookmarks. A bookmark can represent a set of +;; variables and their values. +;; +;; - Snippet bookmarks. Select some some text and give it a +;; (bookmark) name. Then copy it to the `kill-ring' anytime, in +;; any Emacs session. +;; +;; - Icicles search-hits bookmarks. (You need library Icicles to +;; use this feature.) During Icicles search you can use `C-x +;; C-M->' to save the current set of completion candidates +;; (search hits matching your current input) as an Icicles +;; search-hits bookmark. During a later Icicles search you can +;; retrieve those search hits saved in the bookmark, by using +;; `C-x C-M-<`. You can add to (instead of replacing) the +;; current set of hits with hits retrieved from a bookmark using +;; `C-x C-<'. This is the only way you can "jump" to such a +;; bookmark. +;; +;; In particular, note that you can use the following kinds of +;; bookmarks to quickly switch among different projects (sets of +;; bookmarks): Dired, Dired tree, bookmark-list, bookmark-file, +;; and desktop bookmarks. +;; +;; * Type-specific jump commands. +;; +;; - When you want to jump to a bookmark of a specific type +;; (e.g. Dired), you can use a command that offers only such +;; bookmarks as completion candidates. +;; +;; - You can also use generic command `bmkp-jump-to-type', bound +;; to `C-x j :'. It prompts you for the bookmark type, then +;; offers only bookmarks of that type as completion candidates. +;; +;; * Define your own new bookmark types. +;; +;; Just as for vanilla Emacs, you can easily define your own +;; bookmark types, by defining a function to create its record, +;; using function `bookmark-make-record', or by binding variable +;; `bookmark-make-record-function' for a given context. +;; +;; But you can also make jumping to a new type of bookmarks +;; type-specific, usable with `bmkp-jump-to-type' (`C-x j :') or +;; with your own type-specific jump command. +;; +;; For that, just: +;; +;; 1. Define a function `bmkp-TYPE-alist-only', which returns an +;; alist of bookmarks that are only of your new TYPE, for use +;; with `bookmark-completing-read'. The alist should have the +;; same form as `bookmark-alist'. (And you can use your alist +;; for more than just completion.) +;; +;; 2. Evaluate `(bmkp-define-history-variables)', to add a history +;; variable for your type, again, for use with +;; `bookmark-completing-read'. +;; +;; * Extensive menus. +;; +;; - In the `*Bookmark List*' display, a `mouse-3' popup menu has +;; actions for the individual bookmark that you point to when +;; you click the mouse. +;; +;; - In the `*Bookmark List*' display, a complete menu-bar menu, +;; `Bookmark+', is available. The same menu is available on +;; `C-mouse-3'. It has submenus `Jump To', `Mark', `Omit', +;; `Show', `Sort', `Tags', `Highlight' (needs library +;; `bookmark+-lit.el), and `Define Command'. +;; +;; - The vanilla `Bookmarks' menu, which is typically a submenu of +;; the menu-bar `Edit' menu, is modified by adding several items +;; from the `Bookmark+' menu, including submenus `Jump To', +;; `Tags', and `Highlight'. +;; +;; - Bookmark+ adds two items to the menu bar `Edit' menu: +;; +;; . Save the active region text as a bookmark. +;; . Jump to the bookmark to copy the text to the kill ring, so +;; you can then yank it anywhere. +;; +;; - Some modes provide a `Bookmarks Here' menu-bar submenu with +;; items to access bookmarks for the current file/buffer. +;; Display of this menu is controlled by option +;; `bmkp-add-bookmarks-here-menu-flag' (`nil' by default +;; because computing the menu can take a little time). +;; +;; * Improvements for the bookmark-list display. +;; +;; This is buffer `*Bookmark List*', aka the bookmark "menu list" +;; (a misnomer), which you display using `C-x x e' (or `C-x r l'). +;; See (@> "The Bookmark List Display"). +;; +;; - The last display state is saved (by default), and is restored +;; the next time you show the list. (Tip: Use the bookmark list +;; as your "Home" page at Emacs startup.) +;; +;; - You can save the current bookmark-list state at any time and +;; return to it later. There are a few ways to do this, +;; including bookmarking the list itself. +;; See (@> "Bookmark-List Views - Saving and Restoring State"). +;; +;; - Marking/unmarking is enhanced. It is similar to Dired's. +;; +;; - You can easily mark or show different classes of bookmarks. +;; +;; - Faces distinguish bookmarks by type. +;; +;; - You can sort bookmarks in many ways. You can easily define +;; your own sort orders, even complex ones. +;; +;; - You can regexp-search (`M-a') or query-replace (`M-q') the +;; targets (destination file or buffers) of the marked +;; bookmarks, in the current bookmark-list sort order. For +;; Emacs 23 and later, you can even search incrementally (`M-s a +;; C-s', or `M-s a C-M-s' for regexp). +;; +;; - You can use `M-d >' to open Dired for just the local file +;; bookmarks that are marked (`>'). +;; +;; - If you use Emacs on Microsoft Windows, you can open bookmarks +;; according to Windows file associations. (You will also need +;; library `w32-browser.el'.) +;; +;; - You can use (lax) completion when you set a bookmark using +;; `C-x r m' (`bmkp-bookmark-set-confirm-overwrite'), choosing +;; from existing bookmarks for the same buffer. This makes it +;; easy to update a nearby bookmark (e.g. relocate it). With a +;; numeric prefix argument (or if there are no bookmarks for the +;; buffer), you can choose from all bookmarks. +;; +;; - You can edit a bookmark: its name and file name/location, its +;; tags, or its complete defining internal Lisp record. +;; +;; - The mode line shows the number of bookmarks that are marked +;; (`>'), flagged for deletion (`D'), tagged (`t'), temporary +;; (`X'), annotated (`a'), and modified (unsaved) (`*'). It +;; also shows the current sort order. +;; +;; For each of the number indicators (e.g., the number marked): +;; +;; If the current line has the indicator (e.g. `>') and there +;; are other lines with the same indicator that are listed after +;; the current line, then the indicator shows `N/M', where N is +;; the number indicated through the current line and M is the +;; total number indicated. Otherwise, it shows just `N'. +;; +;; This feature is available starting with Emacs 24.3. (For +;; prior versions I removed it because Emacs bug #12867 can +;; cause Emacs to crash.) +;; +;; * Multiple bookmark files. +;; +;; - Although vanilla Emacs lets you load different bookmark +;; files, it does not support this feature well, and the +;; behavior can even be contradictory. With Bookmark+ you can +;; easily (a) switch among alternative bookmark files or (b) +;; load multiple files into the same session, accumulating their +;; bookmark definitions. The last file you used is the default +;; when you choose a file to switch to, so it is easy to go back +;; and forth between two bookmark files. +;; See (@> "Using Multiple Bookmark Files"). +;; +;; * Dedicated keymaps as prefix keys. +;; +;; - Prefix `C-x x' is used for bookmark keys, in general. The +;; vanilla keys on prefix `C-x r' are still available also, but +;; that prefix is shared with register commands, making it less +;; convenient for bookmarks. Using `C-x x' lets you focus on +;; bookmarks. +;; +;; - Prefix `C-x x c' is for setting various kinds of bookmarks. +;; +;; - Prefixes `C-x j' and `C-x 4 j' (for other-window) are used +;; for bookmark jump commands. Again, a dedicated prefix key +;; helps you focus on one kind of action (jumping). +;; +;; All of these prefix keys correspond to prefix-map variables, so +;; you need not use these particular prefixes. You can bind these +;; maps to any prefix keys you want. These are the maps, together +;; with their predefined bindings. +;; +;; `bookmark-map' - `C-x x' +;; `bmkp-set-map' - `C-x x c' +;; `bmkp-tags-map' - `C-x x t' +;; `bmkp-jump-map' - `C-x j' +;; `bmkp-jump-other-window-map' - `C-x 4 j' +;; +;; Those are the prefix keys that are available by default. To +;; change them, just customize these user options, each of which +;; is a list of the key sequences to use as prefix key. +;; +;; - `bmkp-bookmark-map-prefix-keys' - default: ("^Xp") +;; - `bmkp-jump-map-prefix-keys' - default: ("^Xj") +;; - `bmkp-jump-other-window-map-prefix-keys' - default: ("^X4j") +;; +;; (`^X' here is actually the Control-X character.) +;; +;; Keymaps `bmkp-set-map' and `bmkp-tags-map' are always on +;; `bookmark-map', whatever prefix keys it is on. So if, for +;; example, you customize `bmkp-bookmark-map-prefix-keys' to be +;; ("^Xp" [f9]) then the keys in `bmkp-set-map' have both prefix +;; `C-x x c' and prefix ` c'. +;; +;; In addition to keys on Bookmark+ keymaps, Bookmark+ binds some +;; mode-specific bookmarking commands in some other modes: Occur, +;; Compilation (including Grep), Buffer-menu, EWW, Gnus, Info, +;; Man, Woman, W3M, and Dired (if you use library `Dired+'). +;; These keys let you set or jump to bookmarks specific to the +;; modes. +;; +;; * Helpful help. +;; +;; - Information about individual bookmarks. +;; +;; . Anywhere in Emacs, `C-x h M' (command +;; `bmkp-describe-bookmark') describes any bookmark. With a +;; prefix argument, it shows you the full information that +;; defines it (internal form). +;; +;; . With the cursor on a highlighted bookmark, `C-x x ?' shows +;; the same description, and a prefix argment has the same +;; effect (show internal form). +;; +;; . Hovering your mouse over a highlighted bookmark shows the +;; same description, in a tooltip. Actually, you can +;; customize the description using option +;; `bmkp-tooltip-content-function'. The default value is +;; `bmkp-bookmark-description', which describes the bookmark. +;; A value of `bmkp-annotation-or-bookmark-description', for +;; example, shows the bookmark annotation if there is one, or +;; the full description if not. +;; +;; . In the bookmark list, `C-h RET' (or `C-h C-RET') describes +;; the bookmark under the cursor. The description is as +;; complete as possible - for example, for an image-file +;; bookmark the complete EXIF image metadata is shown. (This +;; is only for Emacs 22 and later, and only if you have +;; command-line tool `exiftool' installed. See standard Emacs +;; library `image-dired.el' for more information about +;; `exiftool'.) +;; +;; And again, a prefix arg (`C-u C-h RET') means show the full +;; (internal) bookmark information. +;; +;; `C-h >' shows the same information that `C-h RET' shows, +;; but for all of the marked bookmarks, in the current sort +;; order. That is, it describes each of the marked bookmarks. +;; +;; `C-down' and `C-up' move the cursor down and up a line, +;; respectively, but they also show the description of the +;; bookmark corresponding to the new cursor location. This is +;; a quick way to cycle among bookmark descriptions, in the +;; current sort order. +;; +;; - General Bookmark+ documentation. +;; +;; . Anywhere in Emacs, `M-x bmkp-bmenu-mode-status-help' shows +;; detailed information about the current state of the +;; bookmark list. Click button `Doc in Commentary' or button +;; `Doc on the Web' to access the complete documentation. +;; +;; (Use button `Customize' to customize all Bookmark+ +;; faces and options.) +;; +;; . In the bookmark list, `?' and `C-h m' are the same as `M-x +;; bmkp-bmenu-mode-status-help'. (`C-h m' in the bookmark +;; list does not show you info about minor modes. If you want +;; that, use `M-x describe-mode'.) +;; +;; . In the `bookmark-plus' group customization buffer (`M-x +;; customize-group bookmark-plus'), click button `Commentary'. +;; +;; . From the Emacs-Wiki Web site, +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; - It is easy to recognize orphaned and invalid bookmarks. +;; +;; . Invalid bookmarks are shown in a special face in the +;; bookmark-list display. +;; +;; . You can easily mark all of the orphaned bookmarks, that is, +;; those whose recorded files have been renamed or deleted. +;; You can then relocate or delete those bookmarks. +;; +;; - It is easy to recognize modified (i.e., unsaved) bookmarks. +;; They are marked with `*'. Likewise, bookmarks that have tags +;; (marked with `t'); bookmarks that have annotations (`a'); and +;; bookmarks that are temporary (`X'), meaning that they will +;; not be saved. +;; +;; * Jump-destination highlighting. +;; +;; - When you jump to a bookmark, the destination (position) is +;; highlighted temporarily using crosshairs, to make it stand +;; out. Option `bmkp-crosshairs-flag' controls this, and this +;; feature is available only if you also use library +;; `crosshairs.el'. +;; +;; * Visual bookmarks (highlighting). +;; +;; - You can highlight the locations of bookmarks, either +;; automatically or on demand. You control what kind of +;; highlighting, if any, is used for which bookmarks. This +;; feature requires that you have library `bookmark+-lit.el' in +;; your `load-path' (it will then be loaded by `bookmark+.el). +;; +;; * Better, user-configurable bookmark-name defaults. +;; +;; See the doc strings of command `bookmark-set' (Bookmark+ +;; version) and options `bmkp-new-bookmark-default-names' and +;; `bmkp-default-bookmark-name'. +;; +;; * Synergy with `Icicles'. +;; +;; - `Icicles' works with Bookmark+ to provide enhanced bookmark +;; jumping (visiting), setting, and help. It gives you a +;; bookmark browser, and lets you bookmark and tag files on the +;; fly. See (@> "Use Bookmark+ with Icicles") and +;; https://www.emacswiki.org/emacs/Icicles. + +;;(@* "Bookmark Basics") +;; ** Bookmark Basics ** +;; +;; Bookmark+ builds on vanilla Emacs bookmarks. If you are familiar +;; with the latter, then you can skip this section, which mostly +;; reviews the former. However, this section also introduces some +;; Bookmark+ concepts and features that are detailed in other +;; sections. +;; +;; In Emacs bookmarking these three things are different but related: +;; +;; 1. the bookmark list +;; 2. the bookmark file +;; 3. the bookmark-list display (buffer `*Bookmark List*', aka the +;; bookmark "menu list", a misnomer) +;; +;; It is important to keep these three straight and understand their +;; differences in practice, in particular, when they do and do not +;; represent the same set of bookmarks. +;; +;; #1 is in memory. It is the current set of bookmarks. When you +;; add, rename, delete, etc. a bookmark, this list is updated. +;; +;; #2 is on disk. It is a persistent record of a set of bookmarks. +;; +;; The bookmark list (#1) is the current value of internal variable +;; `bookmark-alist'. The bookmark file (#2) can be anywhere. Its +;; default filename is the value of user option +;; `bookmark-default-file'. +;; +;; The bookmark list is typically initialized from the bookmark file +;; - referred to as loading your bookmarks, but you can also create +;; bookmarks (adding them to the list) without ever saving them to +;; disk. +;; +;; The bookmark list can be saved to the bookmark file - referred to +;; as saving your bookmarks - either automatically or on demand. But +;; it is not necessarily saved. Even if it has been saved in the +;; past, that does not mean that at any given time the bookmark list +;; corresponds exactly to the bookmark file. +;; +;; The list and the file can often become out of sync. In an Emacs +;; session, the bookmark list rules. After an Emacs session, the +;; bookmark file rules (it is all there is). You can use `C-x x L' +;; (`bmkp-switch-bookmark-file-create') to sync (revert) the list to +;; reflect the file - just accept the default value, "switching" to +;; the same file. +;; +;; The bookmark-list display (#3) is a snapshot view of the bookmarks +;; in the bookmark list. As such, what you see there reflects the +;; state of the bookmark list at some point in time. So here again, +;; the two, list and display, can be out of sync. Hitting `g' in the +;; bookmark-list display refreshes it to accurately reflect the +;; current bookmark list (#1). Some other operations in the display +;; also keep it synced with the list. +;; +;; Using a prefix argument (`C-u g') syncs the display (#3) and the +;; list (#1) to the file (#2). This can be useful when some other +;; process (e.g., another Emacs session) updates the bookmark file or +;; when you want to abandon changes to the current bookmark list and +;; any of the current bookmarks. Outside the bookmark-list display, +;; you can use command `bmkp-revert-bookmark-file' to do this. +;; +;; You can load different bookmark files, either adding their +;; bookmarks to those already in the current bookmark list or +;; replacing them. +;; +;; The most important takeaway from this section is that #1 (list), +;; #2 (file), and #3 (display) can be out of sync, and they often +;; are. And that can be useful. +;; +;; Until now, everything said in this section is true of vanilla +;; Emacs as well as Bookmark+. Bookmark+ adds some flexibility +;; regarding the use of multiple bookmark files, and it can save the +;; last state of the bookmark-list display for later reuse. +;; +;; The saved state of the display is restored when you show the +;; display after quitting it (`q') in the same session or quitting +;; Emacs, but only if the bookmark file whose location it recorded is +;; the same as the current bookmark file. +;; +;; It would not make sense to display a completely different set of +;; bookmarks from those that are currently loaded. The display must +;; always reflect the current bookmark list (even if it sometimes +;; reflects it imperfectly, because it is a snapshot). So if the +;; bookmark file that is loaded is different from the one that was +;; recorded for the display state, the recorded state is ignored. +;; +;; +;;(@* "Automatic Saving") +;; *** Automatic Saving *** +;; +;; Before getting into the topic of automatic saving, let me say this +;; clearly once: BACK UP YOUR BOOKMARK FILE(S)! +;; +;; (Bookmark+ creates backups when your bookmark file is saved. +;; Until bug #12507 is fixed, vanilla Emacs does not.) +;; +;; I recommend that you set option `bookmark-version-control' to `t', +;; so that you get numbered backups. +;; +;; If you do use numbered backups then you might also want to +;; customize option `delete-old-versions', setting the value to `t', +;; so that you are not bothered by this prompt each time bookmarks +;; are saved: +;; +;; Delete excess backup versions of ? (y or n) +;; +;; See also nodes `Backup Names' and `Backup Deletion' in the Emacs +;; manual. +;; +;; User option `bookmark-save-flag' controls whether and how often to +;; automatically save the bookmark list to the bookmark file, thus +;; syncing the two. You can toggle this option using `M-~' in the +;; bookmark-list display. +;; +;; In the bookmark-list display, you can tell whether individual +;; bookmarks have been modified since the last save: they are marked +;; with `*'. I believe that this indication is robust and accurate +;; (if not, please report a bug), but a word of caution: do not +;; depend on it. The only way to be sure that your bookmarks have +;; been saved is to save them. ;-) +;; +;; Is there a way to unmodify a single bookmark that you have +;; changed? No, not unless it is the only one you modified. If you +;; revert to the bookmarks as last saved, then all changes to all +;; bookmarks (including addition and removal of bookmarks) are lost. +;; If you want to work carefully when making multiple changes, then +;; save any modifications you are sure of before you move on to +;; others. If only one bookmark is modified then reverting to the +;; bookmark file effectively unmodifies that bookmark. +;; +;; When you consult the doc for option `bookmark-save-flag' you see +;; that besides values of `nil' and `t', meaning off and on, it can +;; have a value that is the number of bookmark modifications to allow +;; before automatically saving. If the value is 10, for instance, +;; then the 11th modification triggers automatic saving. +;; +;; But a modification means any change to any bookmark. Typically, +;; you are more interested in considering all of the changes caused +;; by a given command as one modification. Why? Suppose you use a +;; command such as `T > +' (`bmkp-bmenu-add-tags-to-marked'), which +;; adds a set of tags to each of the marked bookmarks. Even if there +;; have been no other modifications since you last saved bookmarks, +;; if there are more marked bookmarks than your setting of +;; `bookmark-save-flag' then automatic saving will kick in in the +;; middle of the command. Some of the bookmarks with the added tags +;; will be automatically saved. And that does not give you an +;; opportunity to cancel the changes (e.g., by quitting without +;; saving). +;; +;; This is the reason for option `bmkp-count-multi-mods-as-one-flag', +;; whose default value is `t', which means count all of a sequence of +;; modifications together as one modification, as far as +;; `bookmark-save-flag' is concerned. + +;;(@* "Different Types of Jump Commands") +;; ** Different Types of Jump Commands ** +;; +;; When you jump to a bookmark, you can use completion to specify the +;; bookmark name. `bookmark-jump' and `bookmark-jump-other-window', +;; bound to `C-x j j' and `C-x 4 j j', are general commands. Their +;; completion candidates include all of your bookmarks. With +;; Bookmark+ you can easily have a large number of bookmarks. +;; +;; To provide more specificity, Bookmark+ provides many different +;; bookmark jump commands. If you want to jump to a bookmark of a +;; specific type, such as Info, you can use a Bookmark+ command that +;; is specific to bookmarks of that type: only those bookmarks are +;; completion candidates. +;; +;; There are thus type-specific commands: `bmkp-dired-jump', +;; `bmkp-info-jump', and so on, bound to `C-x j d', `C-x j i', and so +;; on. There are also commands to jump to bookmarks for the current +;; buffer or for particular buffers or files +;; (see (@> "Bookmarks for Specific Files or Buffers")). +;; +;; All bookmark jump commands are bound to keys that have the prefix +;; `C-x j'. There is an other-window version of most jump commands, +;; and it is bound to the same key as the same-window command, except +;; the prefix is `C-x 4 j', not `C-x j'. For instance, +;; `bmkp-dired-jump-other-window' is bound to `C-x 4 j d'. +;; +;; (In the bookmark-list display, you can use just `j' instead of +;; `C-x 4 j', and just `J' (uppercase) instead of `C-x j'.) +;; +;; More precisely, the bookmark jump commands are on the prefix maps +;; `bmkp-jump-map' and `bmkp-jump-other-window-map', which have the +;; default bindings `C-x j' and `C-x 4 j'. You can bind these maps +;; to any keys you like, by customizing options +;; `bmkp-jump-map-prefix-keys' and +;; `bmkp-jump-other-window-map-prefix-keys'. +;; +;; If you do not remember the different type-specfic bindings, you +;; can use commands `bmkp-jump-to-type' and +;; `bmkp-jump-to-type-other-window' (`C-x j :' and `C-x 4 j :'). +;; They work for any type, prompting you first for the type, then for +;; a bookmark of that type (only). +;; +;; There are several commands for jumping to a bookmark with tags. +;; The completion candidates can be those bookmarks that have all +;; tags in a given set, some tags in a given set, all tags matching a +;; regexp, or some tags matching a regexp. You are prompted for the +;; set of tags or the regexp to match. +;; +;; These commands all have the prefix key `C-x j t'. The suffix key +;; is `*' for "all" and `+' for "some". The regexp-matching commands +;; precede the suffix key with `%'. For example, `C-x j t % +' jumps +;; to a bookmark you choose that has one or more tags that match the +;; regexp you input. +;; +;; There are some type-specific jump commands for bookmarks with +;; tags. The key sequences for these include a key that indicates +;; the bookmark type, after the `t' indicating tags. For example, +;; commands for jumping to a file or directory bookmark having +;; certain tags use the prefix `C-x j t f' (`f' for file). Similar +;; commands for autofile bookmarks have prefix `C-x j t a' (`a' for +;; autofile). +;; +;; For example, `C-x j t f % *' jumps to a file or directory bookmark +;; you choose, where all of its tags match a regexp, and `C-x j t a +;; +' finds a file tagged with at least one of the tags you input. +;; +;; In addition to the ordinary autofile "jump" commands, there are +;; `find-file' versions: they read a file name using +;; `read-file-name', instead of completing a bookmark name. - see +;; (@> "Autofile Bookmarks"). These commands are available starting +;; with Emacs 22. +;; +;; Bookmark names are global. File names are not; that is, the +;; nondirectory portion is not. Suppose you have two similar +;; directories with some like-named files, perhaps tagged in similar +;; ways. Imagine image files of your vacations organized in +;; different directories by year. It is sometimes useful to narrow +;; your focus to the file bookmarks in one directory. +;; +;; Commands such as `bmkp-file-this-dir-jump' (`C-x j . f') offer as +;; completion candidates only bookmarks for files and subdirs in the +;; current directory (`default-directory'). For tags, there are +;; equivalent commands. For example, `C-x j t . % *' is the same as +;; `C-x j t f % *', but the destinations are limited to files in the +;; current directory. All of the "this-dir" file jump commands are +;; bound to the same keys as the general file jump commands, but with +;; `.' instead of `f'. +;; +;; Remember that Bookmark+ collects lots of commands on only a few +;; predefined prefix keys, primarily as a mnemonic device. Nothing +;; requires you to use the long key sequence `C-x j t f % *' to visit +;; a file that has a given set of tags. It is expected that you will +;; bind short key sequences to commands that you use often. +;; +;; The `C-x j' and `C-x 4 j' bindings are global. In addition, in +;; some modes `j' is bound to the corresponding type-specific jump +;; command. For example, in Info mode, `j' is bound to +;; `bmkp-info-jump'. (Dired is an exception here: `J' is used +;; instead of `j', since `j' is already taken for `dired-goto-file'.) +;; These commands are also added to the mode's menu-bar menu. +;; +;; In Dired mode, `C-j' is bound to a special Dired-specific jump +;; command, `bmkp-dired-this-dir-jump', whose destinations all use +;; the current directory (`default-directory'). The aim of `C-j' is +;; not to change directories but to change to a different set of +;; Dired markings, switches, inserted subdirectories, or hidden +;; subdirectories for the same Dired directory. +;; +;; In addition to the predefined bookmark types, which you can use as +;; described above, you can define a "type"-specific jump command for +;; any set of bookmarks. That is, you can use any specific set of +;; bookmarks as the completion candidates for a new jump command. +;; Such a set is really only a pseudo-type: the actual bookmarks can +;; each be of any type. +;; +;; You could use this feature, for example, to define a jump command +;; for the bookmarks that belong to a given project. +;; +;; One way to define such a command is to first mark the bookmarks +;; that you want to be the completion candidates, then use `C-c C-j' +;; (command `bmkp-bmenu-define-jump-marked-command') in the bookmark +;; list. +;; +;; The `*Bookmark List*' display defines a set of bookmarks, even +;; without markings. So does each bookmark of type bookmark list, +;; that is, a bookmark corresponding to a particular `*Bookmark +;; List*' display state - see +;; (@> "State-Restoring Commands and Bookmarks"). +;; +;; You can capture the set of bookmarks corresponding to a `*Bookmark +;; List*' display for use in navigation, that is, as the current +;; "navigation list". Navigation here includes jumping and cycling +;; - see (@> "Cycling, Navigation List"). +;; +;; To capture in the navigation list the bookmarks corresponding to +;; either the current `*Bookmark List*' display or a bookmark-list +;; bookmark, use `C-x x B', which is bound to command +;; `bmkp-choose-navlist-from-bookmark-list'. To then jump to a +;; bookmark from such a navigation list, use `C-x j N' or `C-x 4 j N' +;; (`bmkp-jump-in-navlist' or `bmkp-jump-in-navlist-other-window'). + +;;(@* "Bookmark Annotations") +;; ** Bookmark Annotations ** +;; +;; With Bookmark+ you can bookmark many kinds of Emacs object. +;; Bookmarks record locations - that is their primary purpose. They +;; can also record annotations: general free-text descriptions of +;; your choosing. An annotation is thus metadata that is associated +;; with a bookmark. You can use it for any purpose you like. +;; +;; Command `bookmark-show-annotation' shows an annotation in +;; read-only mode. You can use `C-x C-q' in the annotation buffer to +;; switch to edit mode (and back again). +;; +;; You can use command `bookmark-edit-annotation' or `bmkp-annotate' +;; anywhere to edit the annotation for a bookmark. For +;; `bookmark-edit-annotation', you can choose among the bookmarks +;; that already have annotations. With a prefix arg, you can choose +;; any bookmark (and so create an annotation). Using `bmkp-annotate' +;; is the same as using `bookmark-edit-annotation' with a prefix arg. +;; +;; In the annotation edit buffer, make your changes and then use `C-c +;; C-c' to save the result. Use `C-x C-k' if you do not want to save +;; the changes. You can also use `C-x C-q' and then `y' to confirm +;; reverting the changes. +;; +;; Non-`nil' user option `bookmark-automatically-show-annotations' +;; means that a bookmark's annotation is popped up whenever you jump +;; to the bookmark. If the non-`nil' value is `edit' then the +;; annotation buffer is in edit mode; if it is any other non-`nil' +;; value then the buffer is in show (read-only) mode. +;; +;; In the `*Bookmark List*' display, bookmarks with annotations are +;; marked by an `a' to the left of the bookmark name. You can use `a +;; a' to show the annotation for the bookmark on the current line. +;; You can use `a e' to create an annotation or edit an existing +;; annotation for it. You can use `a >' to edit annotations for all +;; of the marked bookmarks. You can use `a A' to show a list of the +;; names and annotations of all annotated bookmarks. +;; +;; A bookmark annotation is stored as part of the bookmark itself. +;; For this reason, you typically want to keep the text fairly short. +;; In Bookmark+, the mode for viewing and editing a bookmark +;; annotation is Org mode, by default. (To change the mode used, +;; customize option `bmkp-annotation-modes-inherit-from'.) +;; +;; You can obtain the effect of using longer annotations, and some +;; other advantages as well, by using "external annotations". These +;; are annotations that are short and serve only as pointers to +;; external files, URLs, or other bookmarks. +;; +;; Whenever you show the annotation of a bookmark (via `a' in the +;; `*Bookmark List*' display, `bookmark-show-annotation', or +;; `bookmark-automatically-show-annotations') and the annotation is +;; such a pointer, the effect is to visit the destination. +;; +;; So for example, you can use bookmarks to one or more Org files to +;; annotate (provide metadata for) one or more other bookmarks. +;; +;; You create an external annotation for a bookmark by using one of +;; these forms as the annotation text. +;; +;; bmkp-annot-url: "FILE" +;; bmkp-annot-url: "URL" +;; bmkp-annot-url: "BOOKMARK" +;; +;; * FILE is an absolute file name. It is handled by +;; `find-file-other-window'. +;; * URL is a URL. It is handled by `browse-url'. +;; * BOOKMARK is the name of a bookmark in the current bookmark +;; alist. +;; +;; The double-quote characters are necessary here, so that you can +;; include characters such as `SPC' in the name. The text must be on +;; the first line of the annotation (not counting the commented +;; instruction lines). It can be preceded only by whitespace. +;; +;; You can include other text in the annotation, after the +;; destination specification, and you can see or edit it when you +;; edit the annotation (e.g., using `C-u a' in buffer `*Bookmark +;; List*'), but it is ignored when the annotation is "shown" (e.g., +;; using `a'). +;; +;; In the `*Bookmark List*' display, `M-down' and `M-up' move the +;; cursor down and up a line, respectively, but they also show the +;; annotation, if any, of the bookmark at the new cursor location. + +;;(@* "Bookmark Tags") +;; ** Bookmark Tags ** +;; +;; In addition to annotating bookmarks with arbitrary metadata, +;; Bookmark+ bookmarks can also be tagged, as a way to organize them, +;; which also means as a way to organize the objects that are +;; bookmarked. +;; +;; By "tagging" and "tag" in this context is meant associating +;; keywords or other text with an object, typically in order to +;; classify or characterize it. Tags are metadata about an object. +;; This notion of tagging is sometimes called "delicious" tagging +;; after the Web site www.delicious.com that popularized it +;; (`https://en.wikipedia.org/wiki/Delicious_(website)'). +;; +;; Be aware that there is another notion of "tag" associated with +;; Emacs: that involving Emacs tags files, which record the locations +;; of function, variable, etc. definitions in source files. There is +;; no relation between the two notions of "tag". +;; +;; A bookmark tag is a string (or a cons whose car is a string - see +;; (@> "Bookmark Tags Can Have Values")). You can add as many tags +;; as you like to any bookmark, and multiple bookmarks can have the +;; same tag(s). In fact, that's the whole idea behind using them for +;; organizing. +;; +;; This feature is unrelated to the fact that bookmarks record +;; locations and are useful for navigating. You can, if you want, +;; use bookmarks to tag files in various ways purely for purposes of +;; organizing them (e.g. into projects), whether or not you ever use +;; the bookmarks as a way to visit them. +;; +;; For example, if you use `Dired+' (library `dired+.el'), then you +;; can use `M-b' (`diredp-do-bookmark') in Dired to create an +;; autofile bookmark for each of the marked files and subdirectories +;; in the Dired buffer. Even if you never use those bookmarks for +;; navigating to their targets, you can use them with tags to +;; organize the targets, and thus operate on subsets of the marked +;; files and subdirectories. +;; +;; And if you use libraries `Dired+' and `highlight.el' then +;; autofiles are highlighted specially in Dired, and the highlighting +;; indicates whether the file is tagged. +;; +;; By default, you create bookmarks without tags and add tags to them +;; later. If you prefer, you can customize option +;; `bmkp-prompt-for-tags-flag' to non-`nil' so that you are prompted +;; to add tags immediately whenever you set (create or update) a +;; bookmark. +;; +;; There are also some commands, such as `bmkp-tag-a-file' (`C-x x t +;; + a') and `bmkp-untag-a-file' (`C-x x t - a'), that always prompt +;; for tags to add or remove. (In general, the key `a' is used in +;; key sequences for autofile bookmarks.) +;; +;; When you are prompted to enter a tag, you type some text then hit +;; `RET'. If you want to include a newline character in the tag +;; itself, use `C-q C-j' (`C-j' is the newline character). You can +;; use `C-q' this way to enter any character. If you do use complex +;; strings as tags then you might prefer to simply edit a bookmark's +;; tags in a separate buffer. You can do that using `C-x x t e' (or +;; `T e' in the bookmark-list display). +;; +;; Whenever you are prompted for a tag you can use completion. The +;; completion candidates available are the tag names defined by +;; option `bmkp-tags-for-completion'. The default value of this +;; option is `current', meaning use only the tags from the bookmarks +;; in the current bookmark list as candidates. You can customize the +;; option to include specific tags or the tags from bookmarks in +;; specific bookmark files. +;; +;; You can use command `bmkp-list-all-tags' to list all of the tags +;; defined by option `bmkp-tags-for-completion' or, with a numeric +;; prefix argument, only the tags corresponding to the current +;; bookmark file. You can list the tag names only or (using a +;; non-negative prefix arg) show the full tag definitions, which +;; include any associated tag values (see (@> "Bookmark Tags Can Have Values") +;; for information about tag values). +;; +;; To make tags more useful, Bookmark+ provides *lots* of commands: +;; commands for adding, removing, copying, pasting, and renaming +;; tags; commands for jumping to bookmarks with particular sets of +;; tags; and commands for marking or unmarking (in buffer `*Bookmark +;; List*') bookmarks that are tagged in various ways. +;; +;; Most commands pertaining to tags are by default on prefix key `C-x +;; p t' - use `C-x x t C-h' to see them. In buffer `*Bookmark +;; List*', commands pertaining to tags are on prefix key `T' - use `T +;; C-h' to see them. And remember that you can use `C-h >' to +;; describe all of the marked bookmarks, in the current sort order. +;; The bookmark descriptions include the tags. +;; +;; When combined with other Bookmark+ commands (e.g. search, +;; query-replace) that apply to the marked bookmarks in the +;; `*Bookmark List*' window, you can really do quite a lot using +;; bookmark tags. Use your imagination! +;; +;; See Also: +;; +;; * (@> "Bookmark Records: What A Bookmark Looks Like") +;; * (@> "Bookmarking the Marked Files in Dired") +;; * (@> "Opening Bookmarks Using Windows File Associations") +;; * (@> "Tag Commands and Keys") +;; +;; +;;(@* "Bookmark Tags Can Have Values") +;; *** Bookmark Tags Can Have Values *** +;; +;; Bookmark tags are simply names (strings) when you create them. +;; Nearly all of the predefined operations that use tags use these +;; names: sorting, marking, jumping, and so on. But you can in fact +;; add an associated value to any tag. This means that a tag can act +;; just like an object attribute or property: it can be a name/value +;; pair. +;; +;; To add a value to a tag that has none, or to change the current +;; value of a tag, you use command `bmkp-set-tag-value', which is +;; bound to `T v' in the bookmark list and bound to `C-x x t v' +;; globally. You are prompted for the bookmark, the tag, and the new +;; value. +;; +;; A tag value can be a number, symbol, string, list, vector, and so +;; on. It can be as complex as you like. It can be any Emacs-Lisp +;; object that has read syntax, that is, that is readable by the Lisp +;; reader. (Everything that is saved as part of a bookmark must be +;; readable; otherwise, your bookmark file could not be read +;; (loaded).) +;; +;; Because tag values can be pretty much anything, you are pretty +;; much on your own when it comes to making use of them. Bookmark+ +;; does not provide predefined functions for using tag values. In +;; general, tag values are something you will use with home-grown +;; Lisp code for your own purposes. +;; +;; However, you can easily make some interactive use of tag values +;; with little effort. You can, for example, define a predicate that +;; tests whether a bookmark has a tag value that satisfies some +;; property (e.g. is a number greater than 3.14159265358979), and +;; then you can use command `bmkp-bmenu-mark-bookmarks-satisfying' to +;; mark those bookmarks. +;; +;; Tags that have the prefix "bmkp-" are reserved - do not name your +;; own tags using this prefix. +;; +;; Currently, "bmkp-jump" is the only predefined bookmark tag. You +;; can give this tag a value that is a function - it is called +;; whenever the tagged bookmark is visited. Any Lisp-readable +;; function value is allowed: a symbol or a lambda expression. +;; +;; For example, to display `Hello!' when a bookmark is visited you +;; can use this: +;; +;; T v bmkp-jump RET (lambda () (message "Hello!")) +;; +;; The function that is the value of a "bmkp-jump" tag is called just +;; after the the standard hook `bookmark-after-jump-hook' is invoked. +;; You can use this tag to invoke functions that are specific to +;; individual bookmarks; bookmarks can thus have their own, extra +;; jump functions. +;; +;; +;;(@* "Hierarchical Structures of Bookmarks?") +;; *** Hierarchical Structures of Bookmarks? *** +;; +;; You can use tags to organize sets of bookmarks in various ways. +;; But what about a simple, hierarchical (tree-shaped) structure like +;; the one that you use for bookmarks in a web browser? You can get +;; a similar effect with Bookmark+ by just using a tag-naming +;; convention such as this: +;; +;; vacation/ +;; vacation/2017/ +;; vacation/2017/winter/ +;; vacation/2017/winter/photos/ +;; vacation/2017/summer/ +;; vacation/2017/summer/photos/ +;; vacation/2018/ +;; ... +;; +;; You need not tag any bookmarks with any particular part of such a +;; pseudo-hierarchy. For example, you might tag some bookmarks with +;; vacation/2017/winter/ and some with vacation/2017/winter/photos/, +;; without bothering to have any that are tagged with just vacation/ +;; or just vacation/2017/. +;; +;; You are not limited to a single tree. You can have a tag such as +;; vacation/2017/winter/ and a tag such as work/projects/2017/alpha/, +;; without any need for those to have a common ancestor. +;; +;; How can you use such a tagging scheme? +;; +;; When you jump to a bookmark using a command that asks for tags, +;; such as `C-x j t +' (`bmkp-some-tags-jump'), you can use +;; completion. So you can, for example, type `vac TAB' to show all +;; of your vacation tags (in `*Completions*'), and drill down, +;; completing more, to pick whichever particular vacation tag you're +;; interested in. This is similar to traversing a web-browser +;; tree-like bookmarks menu. But jump commands that use tags let you +;; match any number of tags at the same time, not just one. +;; +;; Completion against the set of existing tags is also available when +;; you add tags to a bookmark. And if option +;; `bmkp-prompt-for-tags-flag' is non-`nil' then you are prompted to +;; add tags whenever you create or update a bookmark. But unlike the +;; case for web-browser bookmark creation, classifying a bookmark +;; when you create it or update it is optional. You can always add +;; tags later, or not at all. +;; +;; Such a purely conventional, pseudo-hierarchy might sound like a +;; silly hack, but it is at least as quick to use as is adding a +;; bookmark to your tree of browser bookmarks. And it is more +;; useful, because the organization is more flexible and you can have +;; multiple, independent hierarchies. +;; +;; The tagging scheme just described can help you keep track of +;; things, even though it is very simple. There is nothing special +;; about it. You might come up with other conventions for +;; classifying tags, which you find more convenient or more powerful. +;; And remember that tags can be more than just names. They give you +;; the full power of Lisp values - do with them whatever you like. + +;;(@* "Function, Sequence, Variable-List,... Bookmarks") +;; ** Function, Sequence, Variable-List,... Bookmarks ** +;; +;; Bookmarks are typically thought of only as recorded locations. +;; Invoking a bookmark, called "jumping" to it, traditionally means +;; just visiting its location. Bookmark+ looks at bookmarks in a +;; more general way than that. A bookmark is a shortcut of some kind +;; - nothing more. It is typically persistent, but it need not be +;; (see (@> "Temporary Bookmarks")). +;; +;; A given type of bookmark is defined by its handler function, which +;; can do anything you like. We've already seen the examples of +;; region bookmarks, which restore the active region, and Dired +;; bookmarks, which restore Dired markings, switches, inserted +;; subdirectories, and hidden (sub)directories. +;; +;; A "function bookmark" simply invokes some function - any function. +;; You can, for instance, define a window or frame configuration and +;; record the configuration as a bookmark. Then jump to the bookmark +;; to switch contexts. (You can also bookmark a desktop and jump to +;; that.) +;; +;; Function bookmarks might not seem too interesting, since there are +;; other ways to invoke functions in Emacs. But the other features +;; of Bookmark+ combine with this feature. You can, for instance, +;; tag function bookmarks. +;; +;; And you can combine them, invoking the functions sequentially. +;; This is a particular case of using a "sequence bookmark", which +;; simply records a sequence of bookmarks. The bookmarks in a +;; sequence can be of any kind, including other sequence bookmarks. +;; +;; Command `bmkp-make-function-bookmark' (`C-x x c F') creates a +;; function bookmark - you give it a function symbol or a lambda +;; expression. +;; +;; A function bookmark can invoke a keyboard macro instead of a +;; function. With a prefix argument, `bmkp-make-function-bookmark' +;; creates a function bookmark from the last keyboard macro. Jumping +;; to the bookmark executes the keyboard macro. A bookmark is thus +;; one way to make a keyboard macro persistent. +;; +;; If you provide a prefix argument to the bookmark jump command or +;; key that invokes a function bookmark, it is passed along to the +;; function. If the bookmark invokes a keyboard macro then the +;; prefix argument determines how many times the macro is invoked. +;; +;; The most general way to create or update a sequence bookmark is +;; using command `bmkp-set-sequence-bookmark' (`C-x x c s'). You are +;; prompted for the sequence bookmark name and the names of the +;; bookmarks that form its sequence and are thus invoked by it +;; sequentially. +;; +;; If the sequence bookmark already exists then a prefix argument +;; determines whether the bookmarks you name are added to the +;; existing sequence or replace it, and if added, whether before or +;; after the bookmarks already in the sequence. +;; +;; Command `bmkp-wrap-bookmark-with-last-kbd-macro' (`C-x x c C-k') +;; returns a sequence bookmark that invokes a bookmark you name and +;; then invokes the last keyboard macro. You are prompted for the +;; names of both bookmarks. If the sequence bookmark does not yet +;; exist then it is created. (The bookmark to be added to the +;; sequence need not exist yet, and it is not created by adding its +;; name to the sequence.) +;; +;; If you enter the same name for the sequence bookmark and the +;; bookmark to wrap with the keyboard macro, then the macro is simply +;; added to that (sequence) bookmark. +;; +;; For example, if you enter `my-seq' for both of the +;; `bmkp-wrap-bookmark-with-last-kbd-macro' prompts, then the last +;; keyboard macro is added to sequence bookmark `my-seq'. Bookmark +;; `my-seq' need not exist yet, in which case it is created, with the +;; keyboard macro as its only member bookmark. +;; +;; If the bookmark to add to the sequence is itself a different +;; (existing) sequence bookmark, then its member bookmarks are added +;; to the sequence being updated (or created), either before or after +;; its existing members, according to the prefix arg (which is passed +;; to `bmkp-set-sequence-bookmark'). +;; +;; Command `bmkp-bmenu-make-sequence-from-marked' creates a sequence +;; bookmark from the marked bookmarks in the bookmark-list display, +;; in their current order. +;; +;; If you use library `Dired+' (`dired+.el') then you can use command +;; `diredp-do-bookmark-dirs-recursive' to create a Dired bookmark for +;; the current Dired buffer and each of its marked subdirectories. +;; Each of those subdirectories is handled similarly, and so on, +;; recursively. This command also creates a sequence bookmark that +;; includes all of these Dired bookmarks, so that it represents a +;; tree (hierarchy) of Dired buffers that are opened together. This +;; provides an alternative to inserting all of the relevant +;; subdirectories into the same Dired buffer. With a prefix arg, all +;; of the descendent Dired buffers are included, whether or not they +;; are marked. +;; +;; You can also create a function bookmark directly from a keyboard +;; macro, using command `bmkp-set-kmacro-bookmark'. And you can save +;; the current set of keyboard macros as a bookmark, using command +;; `bmkp-set-kmacro-list-bookmark' - jumping to it restores all of +;; the macros'. +;; +;; A variable-list bookmark saves and restores the values of a set of +;; variables. Command `bmkp-set-variable-list-bookmark' prompts you +;; for the variables to include in the list and then sets the +;; bookmark. Command `bmkp-jump-variable-list' (`C-x j v') restores +;; the recorded variable values for the bookmark's buffer. You can +;; also create variable-list bookmarks non-interactively, using +;; function `bmkp-create-variable-list-bookmark'. +;; +;; If you use library `zones.el', then you can move among multiple +;; restrictions (narrowings) in a buffer. The restrictions are +;; stored in buffer-local variable `zz-izones'. Command +;; `bmkp-set-izones-bookmark' bookmarks this value for the current +;; buffer. Jumping to such a bookmark restores the saved ring/stack +;; of restrictions. +;; +;; +;;(@* "Little Persistent Named Nothings") +;; *** Little Persistent Named Nothings *** +;; +;; OK, so a bookmark need not "go" anywhere. Function, sequence, +;; variable-list, and some other kinds of bookmarks have no real +;; "location" to move to or restore. But the bookmarks talked about +;; so far at least have an associated action: you can "jump" to them, +;; even if "jump" can mean a arbitrary action that might have nothing +;; to do with reaching a destination. +;; +;; You can also have a *non-invokable* bookmark, that is, one that +;; you cannot jump to. This is a bookmark whose handler is the +;; function `ignore', which does nothing. +;; +;; What's the point of that? To record something persistently, +;; without needing to manage the file(s) you record it in, and to be +;; able to access that something by name. +;; +;; As an example, library Isearch+ provides one such use case. It +;; lets you interactively add, modify, and remove Isearch filter +;; predicates on the fly, providing more power and flexibility in +;; searching. +;; +;; (A filter predicate is a function that accepts the current +;; search-hit limits as arguments. If it returns `nil' then that +;; search hit is excluded from searching; otherwise it is included.) +;; +;; You can also, on the fly, encapsulate the current suite of filter +;; predicates as a new filter predicate. That is, you can manipulate +;; a complex sequence of filters as a single predicate, using a +;; simple name. And you can save the definition of that new +;; predicate in a file, so you can use it again in future Emacs +;; sessions. +;; +;; Alternatively, you can just bookmark the search predicate. The +;; data saved in the bookmark is the suite of filters that is the +;; advised value of `isearch-filter-predicate' at the time of +;; bookmarking. +;; +;; Then, in a future Emacs session, while Isearching you can hit a +;; key and enter the bookmark name (with completion), to apply that +;; suite of filters again. +;; +;; Bookmarking is easier than defining a new predicate and bothering +;; with a file to save it in. This is the kind of thing that +;; bookmarks are for: persistently saving named bits of data for +;; later retrieval by name. +;; +;; Because the saved data in this case (the filter definition) has no +;; use outside the context of searching, there is no way to invoke it +;; - no jump action. Its handler is `ignore'. +;; +;; You can apply all Bookmark+ features to non-invokable bookmarks: +;; sort, edit, tag - whatever. Use Bookmark+ to organize them, even +;; if you cannot invoke them. +;; +;; Non-invokable bookmarks are shown using face `bmkp-no-jump' in the +;; bookmark-list display. +;; +;; It is also possible for a bookmark to have a handler other than +;; `ignore', so that it is invokable, but that its jump action is +;; appropriate only in certain contexts. This is the case, for +;; instance, for an Icicles search-hits bookmark. You cannot invoke +;; it outside the context of Icicles searching. For this reason, +;; these bookmarks are also shown with face `bmkp-no-jump' in the +;; bookmark-list display. + +;;(@* "Editing Bookmarks") +;; ** Editing Bookmarks ** +;; +;; In vanilla Emacs, you can edit the annotation associated with a +;; bookmark. And you can rename a bookmark. But that is all. There +;; is no easy way to really edit a bookmark. +;; +;; With Bookmark+: +;; +;; * You can use `r' in the bookmark-list display (or `C-x x r' +;; elsewhere) to edit the name and the target file name (bookmarked +;; location) of a bookmark. You are prompted for the new names. +;; +;; * You can use `e' in the bookmark-list display (or `C-x x E' +;; elsewhere) to edit a complete bookmark - all of its information. +;; You edit the internal Lisp sexp that represents the bookmark +;; record. This is the same internal definition that you see when +;; you use `C-u C-h RET' in the bookmark list. +;; +;; * You can use `E' in the bookmark-list display to edit the +;; bookmark records of all of the marked bookmarks. Again, this +;; means editing their internal Lisp sexps. In particular, this +;; gives you an easy way to edit tags across multiple bookmarks. +;; All of the editing power of Emacs is available. +;; +;; * You can use `T e' in the bookmark list (or `C-x x t e' +;; elsewhere), to edit a bookmark's tags. +;; +;; For all but the first of these, you are placed in a separate +;; editing buffer. Use `C-c C-c' when you are done editing, to save +;; your changes. (To cancel, just kill the buffer: `C-x k'.) +;; +;; You can also clone (duplicate) a bookmark, using `M-n', and then +;; edit any parts of it (e.g. using `e'). By default, the clone has +;; the same name, but with "<2>" appended. With a prefix arg you are +;; prompted for the name. Outside of the bookmark list you can use +;; `C-x x 2' to clone a bookmark. +;; +;; There are many more keys and commands for editing bookmark tags. +;; You can copy tags (`C-x x t c') from one bookmark and paste them +;; to others, either replacing the original tags (`C-x x t C-y') or +;; adding to them (`C-x x t q'). You can be prompted for some tags +;; to add (`T +') or remove (`T -') from a bookmark. You can delete +;; a tag from all bookmarks (`T d'). You can rename a tag everywhere +;; (`T r'). And you can set a tag's value. +;; +;; As usual, all such commands are also available on the Bookmark+ +;; menus. The menus provide quick reminders of the available keys, +;; as does the help from `?' in the bookmark-list display. +;; +;; +;;(@* "Bookmark Records: What A Bookmark Looks Like") +;; *** Bookmark Records: What A Bookmark Looks Like *** +;; +;; It's worth dispelling some of the mystery about what a bookmark is +;; by mentioning what it looks like. This can help when you edit a +;; bookmark record. The first thing to mention is that the basic +;; structure of a bookmark record is described in the doc string of +;; variable `bookmark-alist' - but I'll repeat some of that info +;; here. +;; +;; A bookmark record is nothing more than a list whose first element +;; is a string, the bookmark name. The other list elements are +;; properties: key+value pairs that define the bookmark data. Each +;; such pair is a cons: a nonempty list or a dotted list. +;; +;; The car of the property is its name (a Lisp symbol). The cdr is +;; its value. What the value can be depends on the property - in +;; general it can be any Lisp value (number, string, list, symbol, +;; etc.). A property with a null cdr means the same thing as having +;; no such property present. For example, having the empty property +;; `(tags)' is the same as having no `tags' property at all. +;; +;; There is nothing more to it: properties can be anything you like, +;; provided you provide some code to recognize them and do something +;; with them. +;; +;; Of course, the types of properties you use most (maybe always) are +;; predefined, and the vanilla `bookmark.el' code and the Bookmark+ +;; code recognize and use them. The most important and most typical +;; property is this: `(filename . "/some/file/name.txt")', that is, a +;; cons whose car is the symbol `filename' and whose cdr is the name +;; (a string) of the bookmarked file. +;; +;; With that in mind, you can see that renaming a bookmark just means +;; changing the string that is its car. And relocating a bookmark +;; just means changing the string that is its `filename' - e.g., from +;; `(filename . "/home/foo.el")' to `(filename . "/some/other.xml")'. +;; +;; If you already have a bookmark file, typically `~/.emacs.bmk', +;; take a look at the bookmark records in it. A typical bookmark +;; also has these properties, in addition to `filename': `position', +;; `front-context-string', and `rear-context-string'. You can guess +;; what they are - if not, see the doc string of `bookmark-alist'. +;; +;; A Bookmark+ bookmark typically has some additional properties that +;; you can also guess. Properties `time' and `visits' are updated +;; automatically each time you access the bookmark. +;; +;; Some bookmarks have a `handler' property whose value is a function +;; that "jumps" to the bookmark "location". I put those two terms in +;; quotes here because a handler is really just any function - it can +;; do anything you like, and there need not be any associated +;; location. +;; +;; Some Bookmark+ bookmarks, including autofile bookmarks, just +;; "jump" to a file. The position in the file is unimportant, and +;; "jumping" does not necessarily mean visiting the file with Emacs. +;; In effect, such bookmarks are just wrappers around the file, +;; letting you get the advantage of Bookmark+ features (tags etc.) +;; for a file. Such bookmarks, which you can create using `C-x x c +;; a' or `C-x x c f', contain a `file-handler' property instead of a +;; `handler' property. The difference between the two is that the +;; `file-handler' value is a function (Lisp function or shell +;; command) to be applied to the file, not to the bookmark. +;; +;; Remember: A bookmark is just a persistent bit of information, +;; typically meta-information about a file and a position in that +;; file. +;; +;; I'm mentioning all of this to make the point that you cannot +;; really hurt anything if you edit a bookmark record and you mess +;; things up. The worst you can do is mess up all of your bookmarks +;; by making the file unreadable as Lisp data. (It's always a good +;; idea to back up your bookmark file from time to time.) +;; +;; And if each bookmark record after you edit it is a cons with a +;; string car then your bookmarks are generally OK, even if you might +;; have ruined the details of one or two of them. Suppose you +;; somehow mistakenly delete the `a' in a `filename' property, for +;; instance. No big deal - that bookmark no longer has a +;; recognizable target location, but the other bookmarks are still +;; OK. +;; +;; The most important property for Bookmark+ users (aside from +;; `filename') is probably `tags'. Its value (the cdr) is a list of +;; strings or conses - the bookmark's tags. When you create a tag, +;; it is typically a string (just its name) - e.g. "blue". If you +;; then give it a value as well, it becomes a cons with that string +;; (the name) as car and the value as cdr - e.g. `("blue" . 42)' or +;; `("blue" moonbeam 42)' - here the cdr is the list `(moonbeam 42)'. +;; Here is an example of a `tags' property: `(tags "hegel" ("blue" +;; . honeypot) "darwin")'. Most of the time you will use strings as +;; tags. See also (@> "Bookmark Tags Can Have Values"). +;; +;; When you edit bookmark records, just try to stay away from +;; changing any properties that you are not familiar with. And make +;; sure that when you're done you have a proper Lisp list (open +;; parens closed etc.). If you've never played with Lisp before, do +;; not panic. +;; +;; Be aware if you see dots (`.') that they are important, and they +;; must be surrounded by whitespace: ` . '. The amount of whitespace +;; never matters in Lisp (except inside a string etc.). +;; +;; Such a dot just separates the car of a cons from its cdr. (What's +;; a cons? Just a car with a cdr!) If the cdr is a list then we +;; typically drop the dot and the list's parens: We write `(b)' +;; instead of `(b . ())' and `(a b)' instead of `(a . (b))' or `(a +;; . (b . ()))'. +;; +;; Finally, remember that when you set an existing bookmark again, +;; e.g., you use `C-x r m' and provide the name of an existing +;; bookmark, the existing properties are generally lost. Some are +;; automatically updated. Any that you might have added by editing +;; are lost, and any that are provided by default by the bookmark +;; handler are replaced. The only exceptions to this are the +;; properties listed in option `bmkp-properties-to-keep', which by +;; default means properties `tags' and `annotation'. Any existing +;; tags and annotation are preserved when you update a bookmark. + +;;(@* "Bookmark-List Views - Saving and Restoring State") +;; ** Bookmark-List Views - Saving and Restoring State ** +;; +;; The bookmark list (buffer `*Bookmark List*') provides a view into +;; the set of bookmarks. You can mark, sort, and hide (filter, omit) +;; bookmarks - see (@> "The Bookmark List Display"). The state of +;; the displayed bookmark list can thus change. +;; +;; At different times, and in different contexts, different views can +;; be useful. Bookmark+ lets you save the current state of the +;; displayed list and later restore it. There are a couple of +;; different ways to do this. +;; +;; +;;(@* "Quitting Saves the Bookmark-List State") +;; *** Quitting Saves the Bookmark-List State *** +;; +;; If option `bmkp-bmenu-state-file' is non-`nil', which it is by +;; default, then Bookmark+ remembers the last state of the bookmark +;; list when you quit it or you quit Emacs, and it restores that +;; state when you show the list again (which could be in the next +;; Emacs session). You can think of this feature as your "Home" page +;; for bookmarks, giving you a stepping stone to the files and +;; directories you use most. +;; +;; If, for example, when you quit the bookmark list you are showing +;; only bookmarks to Info nodes and UNIX manual pages, sorted in a +;; particular way, and with some of them marked with `>' for +;; particular processing, then the next time you open the list the +;; same state is restored: the same set of bookmarks is shown, in the +;; same order, with the same markings. Deletion flags (`D') and +;; modification indicators (`*') are purposefully not saved as part +;; of the display state - they are lost when you quit the display. +;; +;; You can turn off this automatic bookmark-list display state +;; saving, if you want, by customizing option `bmkp-bmenu-state-file' +;; to `nil'. And you can toggle this option at any time, using +;; `C-M-~' in the bookmark list (command +;; `bmkp-toggle-saving-menu-list-state'). In particular, if you want +;; your next visit to the bookmark list to start out with a +;; previously recorded state instead of the current state, just hit +;; `C-M-~' before quitting the bookmark list. +;; +;; +;;(@* "State-Restoring Commands and Bookmarks") +;; *** State-Restoring Commands and Bookmarks *** +;; +;; In addition to automatically saving/restoring the final +;; bookmark-list display state, you can save this state at any time, +;; any number of times, for later restoration. This gives you the +;; ability to create multiple persistent views of your bookmarks. +;; +;; There are two ways to do this: +;; +;; * Create a bookmark for the `*Bookmark List*' buffer itself: a +;; bookmark-list bookmark. +;; +;; * Define a command that restores the bookmark-list state. +;; +;; When you use `C-x r m' (`bmkp-bookmark-set-confirm-overwrite') in +;; buffer `*Bookmark List*' to create a bookmark-list bookmark, the +;; current sort order, filter, regexp pattern, title, and omit list +;; are saved as part of the bookmark. (These concepts are described +;; below - see (@> "Bookmark List Display").) Jumping to such a +;; bookmark restores all of these. +;; +;; Alternatively, you can define a command that does the same thing, +;; but without creating another bookmark - use `C-c C-c' +;; (`bmkp-bmenu-define-command') in the bookmark list to do this. +;; You are prompted for the name of the new command. Use the command +;; anytime (including in another Emacs session) to restore the +;; bookmark list. +;; +;; Define any number of such commands for the views you use. The +;; file for saving the definitions (see option +;; `bmkp-bmenu-commands-file') is never overwritten, so you can also +;; add other code to it manually, if you want. The file is read the +;; first time the bookmark list is displayed in a given Emacs +;; session. +;; +;; The state that is saved and restored using a bookmark-list +;; bookmark or a command defined using `C-c C-c' is only a partial +;; state. The current set of markings and some other information are +;; not saved, in order to save disk space and save/restore time. +;; +;; Sometimes, however, you really want to save the entire +;; bookmark-list state, creating a full snapshot. You can use `C-c +;; C-C' (aka `C-c C-S-c', `bmkp-bmenu-define-full-snapshot-command') +;; to do that. This defines a command that restores the bookmark +;; list completely. That is the same thing that happens +;; automatically (by default) whenever you quit the bookmark list (or +;; Emacs), but defining snapshot commands lets you have multiple +;; saved states and switch to them at will. +;; +;; Be aware, however, that full-snapshot command definitions can be +;; quite large, since they each contain a copy of the current +;; bookmark list and any accessory lists (hidden and marked bookmarks +;; etc.). +;; +;; Whether you use `C-c C-c' or `C-c C-C' to define a state-restoring +;; command or you create a bookmark-list bookmark, you can create a +;; sequence bookmark that combines such bookmark-list restoration +;; with activation of other bookmarks. (To include a state-restoring +;; command in a sequence, you need to first create a function +;; bookmark that uses the command, and then include that bookmark in +;; the sequence.) + +;;(@* "Bookmarking without Visiting the Target") +;; ** Bookmarking without Visiting the Target ** +;; +;; There are several use cases for bookmarking a target without +;; visiting it: +;; +;; 1. In an Emacs buffer you come across a reference or a link to a +;; file or a URL. You bookmark the target without bothering to +;; visit it first. You do not really care which position in the +;; file is bookmarked. +;; +;; 2. In Dired, you mark certain files and then bookmark all (each) +;; of them, in one operation. +;; +;; 3. In a compilation buffer (e.g. `*grep*', `*compile*') or an +;; occur or multi-occur buffer (`*Occur*'), you bookmark one or +;; more of the hits. Such a bookmark takes you to the appropriate +;; position in the target file or buffer. +;; +;; 4. You bookmark a file that you might not even be able to visit in +;; Emacs (in the sense of editing it in a buffer) - for example, a +;; music file. "Jumping" to the bookmark performs an operation +;; appropriate to the file - for example, playing music. +;; +;; +;;(@* "Bookmarking a File or a URL") +;; *** Bookmarking a File or a URL *** +;; +;; You can use commands `bmkp-file-target-set' and +;; `bmkp-url-target-set', bound by default to `C-x x c f' and `C-x x +;; c u', to bookmark any file or URL. Completion is available, the +;; default file name or URL being determined by the text at point. +;; In addition to the file or URL, you are prompted for the bookmark +;; name. (In general, the keys `f' and `u' are used in key sequences +;; for file and URL bookmarks, respectively.) +;; +;; +;;(@* "Bookmarking the Marked Files in Dired") +;; *** Bookmarking the Marked Files in Dired *** +;; +;; If you use `Dired+' (library `dired+.el'), then you can bookmark +;; all of the marked files (and subdirectories) in a Dired buffer at +;; once, as autofiles, even if you normally do not or cannot visit +;; those files in Emacs. These keys are available in Dired: +;; +;; `M-b' - Bookmark each marked file +;; `C-M-S-b' (aka `C-M-B') - Bookmark each marked file in a +;; bookmark-file that you specify +;; `C-M-b' - Bookmark each marked file in a +;; bookmark-file you specify, and create +;; a bookmark for that bookmark-file +;; +;; Each of these commands bookmarks each of the marked files and +;; subdirectories as an autofile. By default, the bookmark file used +;; for the latter two commands is in the current directory. +;; +;; If you use multiple `C-u' as a prefix arg for these commands, then +;; you can bookmark all of the files in Dired, regardless of +;; markings, as follows: +;; +;; `C-u C-u' - Use all files in Dired, except directories +;; `C-u C-u C-u' - Use all files and dirs, except `.' and `..' +;; `C-u C-u C-u C-u' - Use all files and all directories +;; +;; `C-M-b' not only bookmarks each of the marked files, it also +;; creates a bookmark-file bookmark for that set of bookmarks. See +;; (@> "Bookmark-File Bookmarks"), below. +;; +;; You can later "jump" to that bookmark to load its set of +;; bookmarks. If you use `C-u' when you jump to it, then you switch +;; bookmark files, so that `C-x x e' (or `C-x r l') displays only the +;; bookmarks created from the marked files. Without `C-u', jumping +;; to the bookmark-file bookmark simply loads its bookmarks into the +;; current set of bookmarks. +;; +;; +;;(@* "Bookmarking Compilation, Grep, and Occur Hits") +;; *** Bookmarking Compilation, Grep, and Occur Hits *** +;; +;; In a similar way, you can bookmark the file or buffer positions of +;; selected hits in a compilation buffer (including `*grep*') or an +;; `occur' or `multi-occur' buffer. +;; +;; `C-c C-b' in such a buffer bookmarks the target of the hit at +;; point. `C-c C-M-b' bookmarks the target of each hit in the +;; buffer. +;; +;; `C-c C-M-b' in these buffers is thus similar to `M-b' in a Dired +;; buffer. Unlike Dired, however, there is no way to mark such hits. +;; Every hit is bookmarked. +;; +;; Nevertheless, you can get the same effect. Just use `C-x C-q' to +;; make the buffer writable (e.g. temporarily), and then remove any +;; hits that you do not want to bookmark. You can remove hits anyway +;; you like, including by `C-k' and by regexp (`M-x flush-lines' or +;; `M-x keep-lines'). +;; +;; See also: (@> "Autonamed Bookmarks - Easy Come Easy Go"), +;; bookmarking occur hits using autonamed bookmarks. +;; +;; +;;(@* "Bookmarking Files That You Cannot Visit with Emacs") +;; *** Bookmarking Files That You Cannot Visit with Emacs *** +;; +;; You use lots of files that you never visit using Emacs, but that +;; you might like to keep track of or access in other ways: music +;; files, image files, whatever. +;; +;; You can define a new kind of bookmark for any file type you are +;; interested in, implementing a bookmark handler for it that +;; performs the appropriate action on it when you "jump" to it. That +;; action needs to be expressible using an Emacs function, but it +;; need not have anything to do with visiting the file in Emacs. +;; +;; When you bookmark a target file that Emacs recognizes as an image +;; or sound file, an appropriate handler is used automatically. +;; +;; After you create individual bookmarks for, say, music or image +;; files, you can use `P B' in the bookmark-list display to show only +;; those bookmarks, and then use `C-x r m' to bookmark that state of +;; the bookmark-list. +;; +;; That bookmark-list bookmark in effect becomes a music playlist or +;; an image library or slideshow. Jump to it anytime you want to +;; listen to that set of music pieces or view those images. And you +;; can use `C-x x B' and then `C-x x next' to cycle among the music +;; pieces or images (slideshow). (See (@> "Cycling the Navigation List").) +;; +;; Together with the use of bookmark tags, this gives you a handy way +;; to organize and access objects of any kind. See (@> "Bookmark Tags"). +;; +;; You use option `bmkp-default-handlers-for-file-types' to control +;; which operation (handler) to use for which file type. This is a +;; set of associations (an alist) with each key being a regexp +;; matching a file name, and with each associated value being a Lisp +;; sexp that evaluates to either a shell command (a string) or an +;; Emacs function (a symbol or lambda form). +;; +;; You can think of `bmkp-default-handlers-for-file-types' as +;; somewhat analogous to `auto-mode-alist'. But it maps file-name +;; patterns to file actions instead of mapping them to buffer modes. +;; And it has an effect only when you use certain commands. +;; +;; The handler for the bookmark created invokes the shell command or +;; the Emacs function with the file name as argument. +;; +;; Here is an example option value: +;; +;; (("\\.ps$" . "gsview32.exe") +;; ("\\.html?$" . browse-url) +;; ("\\.doc$" . w32-browser)) +;; +;; This value causes creation of bookmarks that, when you jump to +;; them, invoke: +;; +;; * shell command `gsview32.exe' on the bookmark's +;; target file if it is PostScript (extension `.ps') +;; +;; * Emacs Lisp function `browse-url' on the file if it is HTML +;; (extension `.htm' or `.html') +;; +;; * Emacs Lisp function `w32-browser' on the file if the file +;; extension is `.doc' (e.g., a Microsoft Word file) +;; +;; The default value of `bmkp-default-handlers-for-file-types' is +;; taken from the value of option `dired-guess-shell-alist-user' +;; (from Dired X). +;; +;; The associations are checked in order, and the first one that +;; matches the given file name is used. You can thus order them to +;; deal with overlapping file-name patterns. +;; +;; If no matching file association is found in +;; `bmkp-default-handlers-for-file-types', and if option +;; `bmkp-guess-default-handler-for-file-flag' is non-`nil' (it is +;; `nil' by default), then Bookmark+ will guess a shell command to +;; use. It does this by matching the file name against +;; `dired-guess-shell-alist-default' (also from Dired X). In Emacs +;; 23 and later, if it finds no shell command that way then it +;; guesses one based on mailcap entries. +;; +;; When a bookmark is created using `C-x x c f' or `C-x x c a' for a +;; file that matches `bmkp-default-handlers-for-file-types', the +;; shell command or Lisp function that "jumps to" (opens) the file is +;; saved in the bookmark as property `file-handler' (not `handler'). +;; +;; +;;(@* "Opening Bookmarks Using Windows File Associations") +;; *** Opening Bookmarks Using Windows File Associations *** +;; +;; If you use Microsoft Windows there is no need to define new +;; bookmark types and handlers, if the action you want is the one +;; that Windows associates with the file. You already have a set of +;; file/program associations, and Bookmark+ recognizes these as +;; alternative handlers. +;; +;; You can thus take advantage of Windows file associations to open +;; bookmarks for files of all kinds. To do this, you also need +;; library `w32-browser.el'. In the bookmark list, the following +;; keys are bound to commands that open bookmarks using the +;; associated Windows `Open' applications: +;; +;; `M-RET' - `bmkp-bmenu-w32-open' +;; `M-mouse-2' - `bmkp-bmenu-w32-open-with-mouse' +;; `M-o' - `bmkp-bmenu-w32-jump-to-marked' +;; +;; Windows file associations are always available to you, in addition +;; to any other file associations that you define using +;; `bmkp-default-handlers-for-file-types' (see +;; (@> "Bookmarking Files That You Cannot Visit with Emacs")). +;; +;; You can thus have two different programs associated with the same +;; kind of file. Your MS Windows file association for PostScript +;; might, for example, use Adobe Distiller to create a PDF file from +;; PostScript, while your `bmkp-default-handlers-for-file-types' +;; association for PostScript might use GhostView to display it +;; directly. +;; +;; Besides using `M-RET' etc. in buffer `*Bookmark List*', if in +;; `bmkp-default-handlers-for-file-types' you register `w32-browser' +;; as the association to use for a given file pattern, then you can +;; use command `bmkp-w32-browser-jump' (not bound, by default) +;; anywhere to open a bookmark whose file name matches that pattern, +;; using its Windows file-association program. +;; +;; You can also specify `w32-browser' as the bookmark "type" when you +;; use command `bmkp-jump-to-type' (`C-x j :'). Either of these +;; approaches gives you a way to use completion to choose a bookmark +;; to open using a Windows file association. +;; +;; Specifying such an association in +;; `bmkp-default-handlers-for-file-types' means that bookmarks for +;; such a file will have a `file-handler' value of `w32-browser', to +;; "jump" to (i.e., open) the file. +;; +;; To set up a given file extension for use this way, add an entry +;; (REGEXP . w32-browser) to option +;; `bmkp-default-handlers-for-file-types', where REGEXP matches the +;; file extension. +;; +;; For example, to make a command such as `bmkp-bookmark-a-file' +;; (`C-x x c a') automatically bookmark `*.doc' files using the +;; associated MS Windows program (typically MS Word), add this entry: +;; ("\\.doc$" . w32-browser). +;; +;; +;;(@* "Autofile Bookmarks") +;; *** Autofile Bookmarks *** +;; +;; An autofile bookmark, or just an autofile, is a bookmark to a file +;; or directory that uses the nondirectory part of its file name (or +;; of its `directory-file-name', if a directory name) as the bookmark +;; name. +;; +;; You can look at an autofile bookmark as just a wrapper around a +;; file or directory: a way to attach meta information (such as tags) +;; to it. But you can use an autofile bookmark much as you would use +;; a file or directory. +;; +;; To create a new autofile bookmark, you can use +;; `bmkp-bookmark-a-file' (aka `bmkp-autofile-set'), which is bound +;; by default to `C-x x c a'. (In general, the key `a' is used in +;; key sequences for autofile bookmarks.) +;; +;; If user option `bmkp-propertize-bookmark-names-flag' is non-`nil', +;; which it is by default with Emacs 21 and later, then you can have +;; multiple bookmarks with the same name. This is important for +;; autofile bookmarks because the bookmark name is only the +;; nondirectory part of the file name. This Bookmark+ feature lets +;; you have different autofile bookmarks for files of the same name +;; in different directories. +;; +;; In addition to the single autofile bookmark that you can create +;; for a given absolute file location, you can of course create +;; additional bookmarks to the same file or directory, using +;; different bookmark names. Among other things, this lets you tag +;; the same file or directory in different ways. +;; +;; You can use `C-x j a' (`bmkp-autofile-jump') or `C-x 4 j a' +;; (`bmkp-autofile-jump-other-window') to visit an autofile bookmark. +;; And there are commands for visiting an autofile that is tagged in +;; certain ways. For example, `bmkp-autofile-some-tags-regexp-jump' +;; (`C-x j t a % +') jumps to an autofile bookmark that has at least +;; one tag matching a given regexp. See (@> "Tagging Files"). +;; +;; You can create autofiles automatically whenever you use an Emacs +;; file-cache command, by customizing user option +;; `bmkp-autofile-filecache'. See the Emacs manual, node `File Name +;; Cache'. +;; +;; This optional bookmark creation can replace adding the file to the +;; cache, or it can be in addition to caching the file. This is done +;; by advising command `file-cache-add-file', which means that it +;; affects also the other Emacs file-cache commands that use that +;; function, directly or indirectly: +;; +;; * `file-cache-add-directory' +;; * `file-cache-add-directory-list' +;; * `file-cache-add-directory-recursively' +;; * `file-cache-add-directory-using-find' +;; * `file-cache-add-directory-using-locate' +;; * `file-cache-add-file-list' +;; +;; See the Emacs manual, node `File Name Cache'. +;; +;; If option `bmkp-autofile-access-invokes-bookmark-flag' is +;; non-`nil' then regular access of a file or directory +;; (e.g. `find-file') invokes the associated autofile bookmark, if +;; there is one. This has the effect of updating the bookmark data, +;; such as the number of visits. The default value of the option is +;; `nil'. To set the option value, either use Customize +;; interactively or use a Customize function. +;; +;; Finally, if you use libraries `Dired+' and `highlight.el' then +;; autofiles are highlighted specially in Dired, and the highlighting +;; indicates whether the file is tagged. +;; +;; +;;(@* "A Type-Aware `find-file'") +;; *** A Type-Aware `find-file' *** +;; +;; User option `bmkp-default-handlers-for-file-types' (see +;; (@> "Bookmarking Files That You Cannot Visit with Emacs")) gives +;; you a way to associate a file type, as determined by the file +;; name (typically its extension) with a default file action. This +;; is like MS Windows file associations, but it is specific to Emacs +;; and Bookmark+. And it is useful for more than just bookmarks. +;; +;; Commands `bmkp-find-file' (`C-x j C-f') and +;; `bmkp-find-file-other-window' (`C-x 4 j C-f') take advantage of +;; this association to open files. If a file name matches no pattern +;; in `bmkp-default-handlers-for-file-types' then these commands act +;; like `find-file' and `find-file-other-window'. Otherwise, the +;; invoke the associated file handler in +;; `bmkp-default-handlers-for-file-types'. +;; +;; Invoking the handler is just what the ordinary autofile jump +;; commands (e.g. `C-x j a') do. But `bmkp-find-file' is different +;; in a couple of ways. +;; +;; Like vanilla `find-file' (`C-x C-f'), `C-x j C-f' and `C-x 4 j +;; C-f' use `read-file-name' to prompt you for the file name. The +;; completion candidates are the names of all of the files in the +;; current directory (`default-directory'), that is, the directory of +;; your current minibuffer input. This includes the names of any +;; autofile bookmarks in the same directory. And like `C-x C-f' you +;; can change directory, navigating up and down the file hierarchy. +;; In sum, these commands are file-aware. +;; +;; The ordinary autofile jump commands on the other hand use +;; `completing-read' to complete your input against all autofile +;; bookmark names, regardless of directory. And since the bookmark +;; names reflect only the relative file names, it is not so easy to +;; distinguish two autofiles with the same name but in different +;; directories. (`Icicles' can help here, BTW.) +;; +;; There is a `bmkp-find-file-' command that corresponds to each +;; `bmkp-autofile-' command. For example, +;; `bmkp-find-file-some-tags-regexp' (`C-x j t C-f % +') corresponds +;; to `bmkp-autofile-some-tags-regexp-jump' (`C-x j t a % +'). All +;; `bmkp-find-file' commands use `C-f' in their key bindings, as a +;; reminder of their reading file names a la `find-file'. +;; +;; But whereas `C-x j C-f' and `C-x 4 j C-f' let you access any file, +;; the other `bmkp-find-file-' commands, which find files that have +;; certain tags, provide only autofiles as completion candidates. +;; That's obvious, since files are tagged by bookmarking them. +;; +;; You can thus use the `C-f' commands to take advantage of +;; file-action associations that you define. But if you want to +;; associate metadata (e.g. tags) with files or directories, then you +;; will want to create autofiles. You can do this when you invoke +;; these commands, by providing a prefix argument. Thus, for +;; example, `C-u C-x j C-f foo.doc' opens file `foo.doc', respecting +;; any handler recorded for it via option +;; `bmkp-default-handlers-for-file-types' - but it also creates an +;; autofile bookmark for it. +;; +;; Whenever an autofile bookmark is used, regardless of whether you +;; access it using a `bmkp-autofile*' command or a `bmkp-find-file*' +;; command, the full bookmark record (including handler) is taken +;; into account. +;; +;; Note, however, that the `C-f' tag commands differ from the `a' tag +;; commands in how the completion candidates are filtered. +;; +;; For the former, `read-file-name' is passed a predicate that is +;; applied to each file name in the directory, filtering out any such +;; candidates that do not satisfy it (e.g., do not have the required +;; tags). +;; +;; This happens before you type any input to match the file name. +;; The predicate checks for a corresponding autofile and checks its +;; tags (depending on the command). If there are lots of files in +;; the current directory, this can take a while. +;; +;; For the latter, similar tests are made, but instead of testing +;; each file in the current directory, these commands test each +;; bookmark in the current bookmark list. If there are lots of +;; bookmarks this can take a while. +;; +;; In some cases a `C-f' command is quicker; in some cases a `a' +;; command is quicker. +;; +;; If you use `Icicles', then the performance hit for `C-f' when +;; there are lots of files in a directory is greatly reduced. This +;; is because `Icicles' applies the filtering predicate after, not +;; before, you type text in the minibuffer. In other words, instead +;; of testing each file in the directory, it tests only the files +;; that match your input. (In addition, if you use `Icicles' then +;; you get multi-command versions of each of these bookmark commands, +;; which means that you can visit more than one file per command +;; invocation.) + +;;(@* "Tagging Files") +;; ** Tagging Files ** +;; +;; Section (@> "Tags: Sets of Bookmarks") covers bookmark tags, which +;; are persistent metadata that you define to help you organize +;; bookmarks into meaningful sets. +;; +;; Section (@> "Autofile Bookmarks") describes autofile bookmarks, +;; which, in effect, let you treat files and directories generally as +;; if they were bookmarks. You can choose a file or directory to +;; visit or act on by its name and location, but also by its bookmark +;; metadata. +;; +;; In particular, you can tag a file or directory - that is, specify +;; tags for its associated autofile bookmark. And you can then visit +;; a file or directory that has a given set of tags. Bookmark+ +;; provides commands that automatically create and manipulate +;; autofile bookmarks, that is, bookmarks that have the same name as +;; the files or directories they tag. +;; +;; Command `bmkp-tag-a-file' (aka `bmkp-autofile-add-tags'), bound by +;; default to `C-x x t + a', prompts you for a set of tags and a file +;; or directory, and creates or sets the corresponding autofile +;; bookmark. Command `bmkp-untag-a-file' (aka +;; `bmkp-autofile-remove-tags'), bound by default to `C-x x t - a', +;; similarly lets you remove specified tags from a file or directory. +;; +;; If you also use library `Icicles', then you can act on multiple +;; files and directories during the same command (a "multi-command"). +;; You can thus all at once tag a set of files and directories the +;; same way, or act on a set of files and directories that are tagged +;; similarly. `Icicles' also lets you create autofiles or add or +;; remove tags, on the fly, whenever you use commands (e.g. `C-x +;; C-f') that access files or directories. +;; +;; If you also use library `Dired+' (`dired+.el') then you can use +;; `C-+' to add tags to the marked files and directories, and `C--' +;; to remove tags from them. You can use `C-M-+' and `C-M--' to do +;; the same thing for the current file. You can also use items from +;; the Dired menus to do these things. +;; +;; Bookmark+ provides two kinds of command for visiting files +;; associated with bookmarks that have tags. +;; +;; The first kind uses bookmarks directly: you choose a bookmark +;; name, not a file name, but the candidates are only file and +;; directory bookmarks. These commands have the prefix `bmkp-file-' +;; or `bmkp-autofile-'. +;; +;; As a special case, commands with the prefix `bmkp-file-this-dir-' +;; limit the choices to bookmarks for files and subdirectories of the +;; current directory. By default, the commands across all +;; directories are on prefix key `C-x j t f', and those for the +;; current directory only are on prefix key `C-x j t .'. See +;; (@> "Different Types of Jump Commands") for more about these +;; commands. +;; +;; The second kind of command is for visiting tagged files, that is, +;; autofile bookmarks, just like the commands with prefix +;; `bmkp-autofile-'. However, these commands do not handle the +;; bookmark as such, but only its associated file or directory. They +;; recognize its tags, but they pay no attention to any special +;; handler or other recorded information. +;; +;; These commands have the prefix `bmkp-find-file-', and they are on +;; the prefix key `C-x j t C-f'. The `C-f' here is intended to +;; remind you of command `find-file' (`C-x C-f'). Like `find-file', +;; they use `read-file-name' to read the bookmark's file name, +;; instead of using `completing-read' to read the bookmark name. +;; +;; Yes, for an autofile bookmark the bookmark name and the relative +;; file name are the same. But `read-file-name' is file-aware, and +;; lets you browse up and down the directory hierarchy. +;; +;; The `bmkp-find-file-' commands are available only for Emacs 22 and +;; later (because they use `read-file-name' with a PREDICATE +;; argument). +;; +;; For example: +;; +;; `C-x j t f % +' is `bmkp-file-some-tags-regexp-jump' +;; `C-x j t . % +' is `bmkp-file-this-dir-some-tags-regexp-jump' +;; `C-x j t a % +' is `bmkp-autofile-some-tags-regexp-jump' +;; `C-x j t C-f % +' is `bmkp-find-file-some-tags-regexp' +;; +;; * The first of these visits any file or directory bookmark that +;; has at least one tag among the tags you specify, and you choose +;; among bookmark names. The file or directory can be anywhere. +;; +;; * The second is similar to the first, but only bookmarks for files +;; in the current directory are completion candidates. +;; +;; * The third is similar to the first, but only autofile bookmarks +;; are completion candidates. +;; +;; * The fourth is similar to the third regarding tags, but it uses +;; `read-file-name', so you can browse up and down the file +;; hierarchy. The completion candidates are file and directory +;; names, not bookmark names. +;; +;; If you use `Icicles', there are similar sets of commands, but they +;; all let you act on multiple files and directories at the same time +;; (multi-commands). For example, you can delete (or byte-compile +;; or...) a set of files and directories according to their tags. +;; +;; Remember that you can create multiple bookmarks for the same file +;; or directory, providing them with different sets of tags. (Only +;; one of the bookmarks is the autofile bookmark.) +;; +;; You can also use multiple bookmark files (the files that record +;; bookmarks). Different projects can thus have different tags for +;; the same sets of files and directories, even using just autofile +;; bookmarks. See (@> "Using Multiple Bookmark Files"). +;; +;; A file or directory bookmark can have any number of tags, and +;; multiple such bookmarks can have the same tag. You can sort, +;; show/hide, or mark files and directories based on their tags. + +;;(@* "Using Multiple Bookmark Files") +;; ** Using Multiple Bookmark Files ** +;; +;; Bookmark-list views (see +;; (@> "Bookmark-List Views - Saving and Restoring State")) provide +;; one way to switch among various sets of bookmarks that you use. +;; But that feature affects only the bookmarks that you see displayed +;; in buffer `*Bookmark List*', not the actual set of available +;; bookmarks. +;; +;; The bookmarks available to you are defined in a bookmark file. By +;; default, they are stored in the file named by option +;; `bmkp-last-as-first-bookmark-file', if non-`nil', otherwise in the +;; file named by option `bookmark-default-file' (`~/.emacs.bmk', by +;; default). +;; +;; If you use only one bookmark file then you never need to load or +;; save it manually. Emacs does that for you automatically. +;; +;; But you can have multiple bookmark files if you want, and at any +;; time you can change the bookmark file that is current. To do +;; that, use `C-x x L' (or just `L' in the bookmark-list display), +;; which is bound to command `bmkp-switch-bookmark-file-create'. +;; Having multiple bookmark files gives you an added degree of +;; flexibility. +;; +;; By default, the last bookmark file you used, in your last Emacs +;; session, is the initial bookmark file that is loaded automatically +;; in your next session. But if you prefer, you can make Bookmark+ +;; always start with the same bookmark file +;; (`bookmark-default-file'). User option +;; `bmkp-last-as-first-bookmark-file' controls this. +;; +;; You can easily see which bookmark file is current at any time: It +;; is shown at the top of buffer `*Bookmark List*', and it is near +;; the top of the help output from command +;; `bmkp-bmenu-mode-status-help', which is what is bound to `?' and +;; `C-h m' in buffer `*Bookmark List*'. +;; +;; When you switch to another bookmark file, the default choice for +;; the file to switch to is the last bookmark file you used (in the +;; same session). So it is trivial to toggle back and forth between +;; two bookmark files: just hit `RET' to accept the default. +;; +;; When bookmarks are saved automatically, or when you save them +;; using `bookmark-save' (`S' in the bookmark-list display or `C-x x +;; s' globally) and you don't use a prefix argument, they are saved +;; in the current bookmark file. +;; +;; You can turn off the automatic saving of the current bookmark +;; file, by customizing option `bookmark-save-flag' to `nil'. And +;; you can toggle this option at any time, using `M-~' in the +;; bookmark list (command `bmkp-toggle-saving-bookmark-file'). +;; +;; Besides using multiple bookmark files as *alternatives*, you can +;; combine them, using them as component bookmark subsets (like +;; modules). To do that, use command `C-x x l' (lowercase `l'), +;; which is bound to `bookmark-load', and do not use a prefix +;; argument. (Using a prefix argument with `C-x x l' is the same as +;; using `C-x x L': it switches bookmark files.) Here too the +;; default is the name of the last bookmark file that you used. +;; +;; In the `*Bookmark List*' display you can use `M-l' to load all of +;; the bookmark files corresponding to the marked bookmark-file +;; bookmarks, in the order in which they are displayed. Any non +;; bookmark-file bookmarks that are marked are ignored. Before +;; loading, if any of your currently loaded bookmarks have been +;; modified then you are asked if you want to save them first, before +;; loading the others. +;; +;; After loading, to avoid confusion and possible mistakes, automatic +;; saving to the current bookmark file is turned off. You can always +;; use `M-~' to turn it back on again. And remember that, as long as +;; you have not saved bookmarks after loading, you can always use +;; `C-u g' to revert to the bookmarks saved in the bookmark file. +;; +;; To create additional bookmark files, to use either as alternatives +;; or as components, you can either copy an existing bookmark file or +;; use `bmkp-empty-file' (`C-x x 0') to create a new, empty bookmark +;; file. If you use `C-x x 0' with an existing bookmark file, then +;; its bookmarks are all deleted - it is emptied. +;; +;; Instead of simply copying a bookmark file, you can use +;; `bookmark-save' with a prefix argument, or use `bookmark-write' +;; (bound to `C-x x w'), to save the currently defined bookmarks to a +;; different bookmark file. +;; +;; However a bookmark file was created, you can switch to it and then +;; add or delete bookmarks selectively, to change its content. +;; Remember too that you can delete bookmarks from the current set +;; using command `bookmark-delete' (`C-x x d') or, in the bookmark +;; list, using `d' plus `x' or marking then `D'. +;; +;; Deleting bookmarks from a bookmark file is one way of editing it. +;; Another is to copy or move bookmarks from one bookmark file to +;; another. In the bookmark-list display, you can copy or move the +;; marked bookmarks (or the current bookmark, if none are marked) +;; from the current bookmark file to another that you name, using `Y +;; > +' (`bmkp-bmenu-copy-marked-to-bookmark-file') and `Y > -' +;; (`bmkp-bmenu-move-marked-to-bookmark-file'), respectively. And +;; you can use `Y > 0' +;; (`bmkp-bmenu-create-bookmark-file-from-marked') to create a new +;; bookmark file by copying the marked bookmarks. With a prefix arg, +;; `Y > 0' creates also a bookmark-file bookmark. +;; +;; In any location (any file or any buffer that can be bookmarked), +;; you can switch to a bookmark file that has only bookmarks for the +;; current file or buffer, creating such a file on the fly if none +;; exists. To do this, use `C-x x C-l' +;; (`bmkp-switch-to-bookmark-file-this-file/buffer'). +;; +;; NOTE: +;; +;; Unlike the other ways of organizing bookmarks into sets (tags, +;; bookmark-list bookmarks, etc.) bookmark files represent +;; physical, not logical, groupings of bookmarks. A bookmark file +;; contains complete bookmark records. +;; +;; If you copy a bookmark from one bookmark file to another, the +;; copy is an independent bookmark: it has no relation to the +;; bookmark it was copied from. Changes to the copy or the +;; bookmark it was copied from do not affect each other. +;; +;; This means that to use bookmark files for organizing bookmarks +;; you will typically move, not copy, bookmarks between them (or +;; copy and later delete). Remember that you can load multiple +;; bookmark files to access their bookmarks together in a session. +;; Think of your bookmark files as independent modules that you can +;; combine. +;; +;; See Also: (@> "Bookmark+ Load Order and Option `bookmark-default-file'"). +;; +;; +;;(@* "Bookmark-File Bookmarks") +;; *** Bookmark-File Bookmarks *** +;; +;; A bookmark file is an excellent, persistent way to represent a set +;; of bookmarks. In particular, it can represent a project or a +;; project component. Switch among bookmark files to access +;; different projects. Load project components as you need them. +;; +;; You can load a bookmark file using `C-x x L' (switch) or `C-x x l' +;; (accumulate). As a convenience, you can also load a bookmark file +;; by jumping to a bookmark-file bookmark. +;; +;; You use command `bmkp-set-bookmark-file-bookmark', bound to `C-x x +;; y', to create a bookmark-file bookmark. Jumping to such a +;; bookmark just loads the bookmark file that it records. With `C-u' +;; (e.g. `C-u C-x j y project-foo'), jumping switches bookmark files. +;; Without `C-u' it accumulates the loaded bookmarks. +;; +;; You can also use commands `bmkp-bookmark-file-load-jump' and +;; `bmkp-bookmark-file-switch-jump' (unbound by default), which load +;; and switch without prompting you for confirmation or whether to +;; first save the current bookmark file. +;; +;; A bookmark-file bookmark is not only an added convenience. You +;; can also use it in combination with other Bookmark+ features, such +;; as tagging. +;; +;; As a shortcut, in Dired (if you use library `Dired+'), `C-M-b' +;; creates a bookmark-file bookmark. The bookmark file that it +;; records contains autofile bookmarks to each of the files and +;; subdirectories that was marked in Dired at the time it was +;; created. Jumping to that bookmark-file bookmark makes those +;; (marked) files and subdirectories available as bookmarks. See +;; also (@> "Use Dired to Bookmark Files without Visiting Them"). +;; +;; Note that the bookmark file in which a bookmark-file bookmark is +;; recorded is not the same as the bookmark file recorded in that +;; bookmark. +;; +;; For example, when you use `C-M-b' in Dired, the bookmark-file for +;; the marked files is, by default, file `.emacs.bmk' in the Dired +;; directory. So if you are in directory `/foo/bar' the default +;; bookmark file for the marked files is `/foo/bar/.emacs.bmk'. But +;; the new bookmark-file bookmark created is recorded in the current +;; bookmark file, whatever that might be (e.g. `~/.emacs.bmk'). + +;;(@* "The Bookmark List Display") +;; ** The Bookmark List Display ** +;; +;; Bookmark+ enhances the bookmark list (aka the bookmark "menu +;; list", a misnomer) that is displayed in buffer `*Bookmark List*' +;; when you use `C-x x e' or `C-x r l' (command +;; `bookmark-bmenu-list'). +;; +;; At the top of the bookmark-list display is this header +;; information: +;; +;; * The bookmark file used currently. This is important because +;; Bookmark+ makes it easy for you to have multiple bookmark files +;; and switch among them. +;; +;; * A title that describes the kinds of bookmarks listed, that is, +;; it reflects athe current filtering, if any. +;; +;; For example, this header indicates that the current bookmark file +;; is `c:/.emacs.bmk' and only file and directory bookmarks are +;; shown: +;; +;; Bookmark file: +;; c:/.emacs.bmk +;; +;; File and Directory Bookmarks +;; ---------------------------- +;; +;; (Bookmark+ does not use the sliding header line of vanilla Emacs +;; 24+, which means that option `bookmark-bmenu-use-header-line' has +;; no effect. You do not need to see `Bookmark' and `File' column +;; headers as you scroll.) +;; +;; Bookmarks are highlighted to indicate their type. You can mark and +;; unmark bookmarks, show or hide bookmarks of particular types, and +;; more. Bookmarks that have tags are marked with a `t'. Bookmarks +;; that have an annotation are marked with an `a' (not with a `*' as +;; in vanilla `bookmark.el'). Bookmarks that have been modified +;; since the last save of the bookmark file are marked with a `*'. +;; Bookmarks that have bookmark-highlight override settings (see +;; (@> "Defining How to Highlight")) are marked with a one-character +;; pink background. +;; +;; Use `?' or `C-h m' in buffer `*Bookmark List*' for more +;; information about the bookmark list, including the following: +;; +;; * The current status of sorting, filtering, and marking. +;; +;; * A legend for the faces used for different bookmark types. +;; +;; +;;(@* "Jumping To Bookmarks from the Bookmark List Display") +;; *** Jumping To Bookmarks from the Bookmark List Display *** +;; +;; Bookmark visiting (jumping) commands are globally on prefix keys +;; `C-x j' and `C-x 4 j'. In the bookmark-list display they are +;; additionally on `j' (other window) and `J' (same window). In +;; addition, `j >' is bound to `bmkp-bmenu-jump-to-marked', which +;; jumps to each of the marked bookmarks in other windows. +;; +;; +;;(@* "Tag Commands and Keys") +;; *** Tag Commands and Keys *** +;; +;; There are lots of tag-related bookmark commands, and most are +;; bound to keys in buffer `*Bookmark List*' as well as to other keys +;; outside it. How can you keep the commands straight or remember +;; their keys? +;; +;; In the bookmark list display, tags-command keys begin with prefix +;; key `T'. Elsewhere, they begin with prefix key `C-x x t' (or `C-x +;; j t', for jump commands - see (@> "Different Types of Jump Commands")). +;; +;; `C-h m' (or `?') is your friend, of course. Likewise `T C-h', +;; `C-x x t C-h', and `C-h >' (which describes the marked bookmarks). +;; Beyond that, the tag-related keys that are more than two +;; keystrokes are organized as follows: +;; +;; They all have the prefix key `T'. +;; +;; `m' means mark +;; `u' means unmark +;; `>' stands for the marked bookmarks +;; `*' means AND (set intersection; all) +;; `+' means OR (set union; some/any) +;; `~' means NOT (set complement) +;; +;; The key `T m *', for instance, marks (`m') the bookmarks that are +;; tagged with all (`*' = AND) of a given set of tags. It prompts you +;; for one or more tags that the bookmarks must have, and it marks +;; all bookmarks that have all of the tags you enter. +;; +;; The key `T u ~ +' unmarks (`u') the bookmarks that do not (`~') +;; have any (`+' = OR) of the tags you specify. And so on. +;; +;; The marking and unmarking commands for tags compare the tags a +;; bookmark has with tags that you enter. Any bookmarks that have no +;; tags are ignored - they are neither marked nor unmarked by these +;; commands. +;; +;; `+' and `-' can also mean add and remove tags, respectively, and +;; `>' stands for the marked bookmarks. So `T > +' adds (`+') one or +;; more tags to each of the marked (`>') bookmarks. +;; +;; In general, the tag-related commands let you enter a set of tags, +;; one at a time. Thus, instead of having a command that adds a +;; single tag to the current bookmark, you have a command that adds +;; any number of tags to it. To add just a single tag, hit `RET' +;; twice: once to enter the tag, and once again to indicate that it +;; is the last (i.e., the only) one. +;; +;; If you just hit `RET' immediately, specifying an empty set of +;; tags, then each of the commands does something appropriate. For +;; `T m *', for instance, an empty list of tags means to mark (only) +;; the bookmarks that have any tags at all. +;; +;; Finally, for the marking/unmarking tags commands, a prefix +;; argument flips the sense of the command, in this way: +;; +;; "some are" -> "some are NOT", i.e., "not all are" (and vice versa) +;; "all are" -> "all are NOT", i.e., "none are" (and vice versa) +;; +;; In other words: +;; +;; C-u T m * = T m ~ + (all are NOT = not some are) +;; C-u T m ~ + = T m * (not some are NOT = all are) +;; C-u T m + = T m ~ * (some are NOT = not all are) +;; C-u T m ~ * = T m + (not all are NOT = some are) +;; +;; You'll figure it out ;-). +;; +;; Other important keys pertaining to tags (the keys in parentheses +;; work in any buffer, not just buffer `*Bookmark List*'): +;; +;; * `C-h RET' (`C-h M') shows you the tags that belong to a +;; bookmark. With a prefix argument it shows you the full internal +;; form of the tags, that is, the name+value pairs. +;; +;; * `C-h >' describes all of the marked bookmarks, in the current +;; sort order. The descriptions include the tags. (You can use `T +;; m * RET' to mark all of the tagged bookmarks.) +;; +;; * `T e' (`C-x x t e') lets you edit a bookmark's tags. +;; +;; * `T l' (`C-x x t l') lists all tags currently known to Emacs +;; (across all bookmarks). +;; +;; * `T +' (`C-x x t + b') adds some tags to a bookmark. +;; `T -' (`C-x x t - b') removes some tags from a bookmark. +;; `T 0' (`C-x x t 0) removes all tags from a bookmark. +;; `T d' (`C-x x t d) removes a set of tags from all bookmarks. +;; +;; In the bookmark list display you can also sort bookmarks according +;; to how they are tagged, even in complex ways. See +;; (@> "Sorting Bookmarks"). +;; +;; +;;(@* "Tags: Sets of Bookmarks") +;; *** Tags: Sets of Bookmarks *** +;; +;; The best way to think about tags is as names of sets. All +;; bookmarks tagged `blue' constitute the bookmark set named `blue'. +;; +;; The bookmarks visible in the bookmark list at any time also +;; constitute an unnamed set. Likewise, the marked bookmarks and the +;; unmarked bookmarks are unnamed sets. Bookmark+ is all about +;; helping you act on sets of Emacs objects. Bookmarks are named, +;; persistent pointers to objects such as files and filesets. +;; Bookmark tags are named, persistent sets of bookmarks (and hence +;; of their target objects). +;; +;; The marking commands make it easy to combine sets as unions or +;; intersections. And you can give the result a name for quick +;; access later, just by adding a new tag. in other words, do the +;; set-definition work only once, and name the result. +;; +;; How would you tag as `Java IDE Projects' the bookmarks that are +;; already tagged both `Java' and `ide'? +;; +;; 1. `T m * Java RET ide RET RET', to mark them. +;; 2. `T > + Java IDE Projects RET RET, to tag them. +;; +;; How would you sort your bookmarks, to show all those tagged both +;; `blue' and `moon' first? +;; +;; 1. `T m * blue RET moon RET RET', to mark them. +;; 2. `s >' to sort the marked bookmarks first +;; (see (@> "Sorting Bookmarks"), below). +;; +;; If you wanted to show only the marked bookmarks, instead of +;; sorting to put them first in the list, you would use `>' +;; instead of `s >'. +;; +;; How would you query-replace the set of files that are tagged with +;; any of the tags `alpha', `beta', and `gamma', but are not tagged +;; `blue' or `moon'? +;; +;; 1. `F S', to show only the file bookmarks. +;; 2. `T m + alpha RET beta RET gamma RET RET', to mark the +;; bookmarks that have at least one of those tags. +;; 3. `T u + blue RET moon RET RET', to unmark those that are +;; tagged `blue' or `moon'. +;; 4. `M-q' to query-replace the marked files. +;; +;; If that were a set of files that you used often, then you would +;; name the set by giving the files a new tag. +;; +;; The point is that bookmarks, and bookmark tags in particular, let +;; you define and manipulate sets of Emacs objects. It doesn't +;; matter how you define such a set: regexp matching (marking, +;; filtering), by object type, by tag combinations... Sets need not +;; be named to act on them, but you can provide them with persistent +;; names (tags) to avoid redefining them over and over. Manipulation +;; of bookmarked objects includes visiting, searching, and +;; query-replacing. And you can define your own bookmark types +;; (using bookmark handlers) and associated manipulations. +;; +;; +;;(@* "Open Dired for the Marked File Bookmarks") +;; *** Open Dired for the Marked File Bookmarks *** +;; +;; You've seen that the bookmark list has many features that are +;; similar to Dired features. But Dired is specialized for files and +;; directories, and it has many more features for manipulating them. +;; The bookmark list is not intended to replace Dired. +;; +;; You can, however, use the bookmark list to take advantage of +;; arbitrary Dired features for file and directory bookmarks. +;; Command `bmkp-bmenu-dired-marked' (`M-d >') weds Bookmark+'s +;; set-defining and set-manipulating features (tagging, marking, +;; filtering etc.) to Dired's file-manipulating features. +;; +;; `M-d >' opens a Dired buffer that is specialized for just the +;; files and directories whose bookmarks are marked in the bookmark +;; list. (Other marked bookmarks are ignored by the command.) The +;; files and directories can be located anywhere; they need not be in +;; the same directory. They are listed in Dired using absolute file +;; names. +;; +;; (In Emacs versions prior to release 23.2, only local files and +;; directories can be handled, due to Emacs bug #5478. In such +;; versions, remote-file bookmarks are ignored by `M-d >'.) +;; +;; This Bookmark+ feature makes sets of files and directories +;; immediately amenable to all of the operations provided by Dired. +;; +;; It is particularly useful in conjunction with tags. Use bookmark +;; tags and marks to define a possibly complex set of file and +;; directory bookmarks. Then hit `M-d >' to list them in a Dired +;; buffer. Then use any Dired commands you want to act on any of +;; them. +;; +;; For example, to compress bookmarked files that are tagged with +;; both `blue' and `moon': +;; +;; 1. Mark them using `T m * blue RET moon RET RET'. +;; 2. Open Dired for them using `M-d >'. +;; 3. Mark them in Dired, then compress them using `Z'. +;; +;; Since tags are persistent, Bookmark+ gives you a good way to +;; define an arbitrary set of files as a project and then open them +;; in Dired at any time to operate on them. +;; +;; If you use `Dired+' (library `dired+.el'), then a similar feature +;; is available for the marked files and directories: You can use +;; `C-M-*' in Dired to open a separate Dired buffer for them only. +;; You can of course then bookmark that resulting Dired buffer, if +;; you like. +;; +;; If you use `Icicles', then whenever you use a command that reads a +;; file (or directory) name, you can use `M-|' during file-name +;; completion to open Dired on the currently matching set of file +;; names. That is, this is the same kind of special Dired buffer +;; that is provided for file and directory bookmarks by `M-d >' in +;; the bookmark list. +;; +;; +;;(@* "Marking and Unmarking Bookmarks") +;; *** Marking and Unmarking Bookmarks *** +;; +;; Bookmark+ enhances the marking and unmarking of bookmarks in the +;; bookmark list in several ways. These enhancements are similar to +;; features offered by Dired and Dired-X. You can use: +;; +;; * `% m' to mark the bookmarks that match a regexp. The entire +;; line in the bookmark list is checked for a match, that is, both +;; the bookmark name and the file name, if shown. +;; +;; * `M-DEL' (or `U') to unmark all bookmarks, or all that are marked +;; `>', or all that are flagged `D' for deletion. +;; +;; * `t' to toggle (swap) the marked and unmarked bookmarks: those +;; that are marked become unmarked, and vice versa. +;; +;; * `>' to show only the marked bookmarks or `<' to show only the +;; unmarked bookmarks. Repeat to show them all again. +;; +;; * `F M', `I M' etc. to mark only the file bookmarks, Info +;; bookmarks etc. (The first key here is the same as the +;; corresponding filter key, e.g. `F' for files - see next topic.) +;; +;; * `O M' to mark the orphaned bookmarks, that is, those whose +;; recorded files have been renamed or deleted. You can then +;; relocate or delete the bookmarks, as appropriate. +;; +;; +;;(@* "Filtering Bookmarks (Hiding and Showing)") +;; *** Filtering Bookmarks (Hiding and Showing) *** +;; +;; There are three ways to show only certain bookmarks. +;; +;; 1. Filter by bookmark type. +;; +;; 2. Filter bookmarks incrementally and temporarily, using pattern +;; matching. +;; +;; 3. Filter out the marked or unmarked bookmarks. +;; +;; * Filtering by bookmark type +;; +;; The commands that show only bookmarks of a particular type are +;; bound to keys that end in `S' (for "show"). For example, `I S' +;; shows only Info bookmarks, and `X S' shows only temporary +;; bookmarks. +;; +;; The type filter is reflected in the bookmark-list display title. +;; It says `All Bookmarks' if no type filter is used. Otherwise it +;; tells you what kind of bookmarks are listed: `Autonamed +;; Bookmarks', `File and Directory Bookmarks', and so on. +;; +;; Note: It is only filtering by bookmark type that is remembered +;; when you save a bookmark-list display state or you create a +;; bookmark-list bookmark. See (@> "State-Restoring Commands and Bookmarks"). +;; +;; * Filtering incrementally by pattern matching +;; +;; These commands show only bookmarks that in some way match a +;; pattern (regexp) that you type. The bookmarks are filtered +;; incrementally as you type the pattern. Hit any non-inserting +;; key, such as `RET', to finish defining the pattern. +;; +;; The commands for this are bound to keys that start with `P' (for +;; "pattern"). For example, `P B' shows only bookmarks whose names +;; match the regexp, `P F' shows those whose file names match, `P +;; A' shows those whose annotations match, and `P T' shows those +;; that have one or more tags that match. (See (@> "Bookmark Tags"), +;; above, for information about tags.) +;; +;; * Filtering based on marking +;; +;; Just as in Dired, you can use `% m' to mark the bookmarks that +;; match a regexp. Then use `>' to show only the marked bookmarks. +;; See (@> "Marking and Unmarking Bookmarks"), above. +;; +;; This method has the advantage that you can show the complement, +;; the bookmarks that do *not* match the regexp, by using `<' +;; instead of `>'. It also has the advantage that matching checks +;; the combination of bookmark name and file name (use `M-t' to +;; toggle showing file names). +;; +;; +;;(@* "Only Visible Bookmarks Are Affected") +;; *** Only Visible Bookmarks Are Affected *** +;; +;; Commands that operate on the current bookmark or on the marked or +;; the unmarked bookmarks act only on bookmarks that are displayed +;; (not hidden). This includes the commands that mark or unmark +;; bookmarks. This means that you can easily define any given set of +;; bookmarks. +;; +;; For example: +;; +;; Use `F S' to show only bookmarks associated with files. +;; Use `% m' to mark those that match a particular regexp. +;; Use `R S' to show only bookmarks that have regions. +;; Use `m' to mark some of those region bookmarks individually. +;; Use `.' to show all bookmarks. +;; Use `t' to swap marked and unmarked (so unmarked are now marked) +;; Use `D' to delete all of the marked bookmarks (after confirming) +;; +;; Together, steps 1-7 delete all file bookmarks that match the +;; regexp and all region bookmarks that you selectively marked. +;; +;; +;;(@* "Omitting Bookmarks from Display") +;; *** Omitting Bookmarks from Display *** +;; +;; In sections (@> "Marking and Unmarking Bookmarks") and +;; (@> "Filtering Bookmarks (Hiding and Showing)") you learned how +;; to hide and show bookmarks in the bookmark list. This section is +;; about a different kind of hiding, called "omitting". +;; +;; Omitted bookmarks are not shown in the bookmark list, no matter +;; what filtering is used. The only way to show omitted bookmarks is +;; to show all of them and only them, using `- S', which is bound to +;; command `bmkp-bmenu-show-only-omitted'. +;; +;; Omitted bookmarks are still available even if they are not shown, +;; and you can still jump to them (e.g. using `C-x r b'). You just +;; don't see them in the bookmark list. And that's the reason for +;; this feature: to hide those bookmarks that you don't care to see. +;; +;; One use for this feature is to hide the component bookmarks that +;; make up a sequence bookmark (see +;; (@> "Function, Sequence, Variable-List,... Bookmarks")). The +;; default behavior when you create a sequence bookmark is in fact to +;; omit its component bookmarks from the displayed list. +;; +;; You can omit any bookmarks by marking them and then using `- >' +;; (`bmkp-bmenu-omit/unomit-marked'). If you are looking at the +;; omitted bookmarks (after using `- S'), then `- >' un-omits the +;; bookmarks marked there. Think of two complementary spaces: the +;; normal bookmark list and the omitted bookmark list. When you use +;; `- >', the marked bookmarks that are currently shown are moved to +;; the opposite space. +;; +;; You can un-omit all of the omitted bookmarks at once, using `- U' +;; (`bmkp-unomit-all'). You can also call this command from outside +;; the bookmark-list display. +;; +;; Omitted bookmarks that are marked are generally not included when +;; you use a command that acts on the marked bookmarks. However, if +;; you use a negative prefix argument with the command then they are. +;; +;; For some commands this is relaxed so that any prefix arg has this +;; effect. For other commands a non-negative prefix arg has a +;; different effect. In some cases, a non-negative prefix arg has +;; one effect and a non-positive prefix arg has the effect of +;; including omitted marked bookmarks, so that a zero prefix arg has +;; both effects. For any given command, consult the doc string for +;; full information. +;; +;; +;;(@* "Sorting Bookmarks") +;; *** Sorting Bookmarks *** +;; +;; Filtering hides certain kinds of bookmarks. Sometimes, you want +;; to see bookmarks of various kinds, but you want them to be grouped +;; or sorted in different ways, for easy recognition, comparison, and +;; access. +;; +;; Bookmarks shown in the bookmark list are sorted using the current +;; value of option `bmkp-sort-comparer'. (If that is `nil', they are +;; unsorted, which means they appear in reverse chronological order +;; of their creation.) +;; +;; You can use `s s'... (repeat hitting the `s' key) to cycle among +;; the various sort orders possible, updating the display +;; accordingly. By default, you cycle among all available sort +;; orders, but you can shorten the cycling list by customizing option +;; `bmkp-sort-orders-for-cycling-alist'. +;; +;; You can also change directly to one of the main sort orders +;; (without cycling) using `s >', `s n', `s f n', etc. There are +;; many such predefined sort orders bound to keys with the prefix `s' +;; - use `C-h m' or `?' for more info. +;; +;; `s >' – Sort marked (`>') before unmarked +;; `s *' – Sort modified (`*') before unmodified +;; `s 0' – Sort by bookmark creation date/time +;; `s b' – Sort by last buffer or file access +;; `s a' – Sort annotated (`a') before unannotated +;; `s d' – Sort by last bookmark access date/time +;; `s D' – Sort flagged (`D') before unflagged +;; `s f d' – Sort by last local file access date/time +;; `s f k' – Sort by local file kind: file, symlink, dir +;; `s f n' – Sort by file name +;; `s f s' – Sort by local file size +;; `s f u' – Sort by last local file update (edit) date/time +;; `s g' – Sort by Gnus thread: group, article, message. +;; `s i' – Sort by Info manual, node, position +;; `s k' – Sort by bookmark type (kind) +;; `s n' – Sort by bookmark name +;; `s t' – Sort tagged (`t') before untagged +;; `s v' – Sort by visit frequency +;; +;; You can reverse the current sort direction (ascending/descending) +;; using `s r'. Also, repeating any of the main sort-order commands +;; (e.g. `s n') cycles among that order, the reverse, and unsorted. +;; +;; For a complex sort, which involves composing several sorting +;; conditions, you can also use `s C-r' to reverse the order of +;; bookmark sorting groups or the order within each group (depending +;; on whether `s r' is also used). Try it, for example, together +;; with sorting by bookmark kind (`s k'). +;; +;; Be aware that `s C-r' can be a bit unintuitive. If it does not do +;; what you expect or want, or if it confuses you, then don't use it +;; ;-). (`s C-r' has no noticeable effect on simple sorting.) +;; +;; Remember that you can combine sorting with filtering different +;; sets of bookmarks - bookmarks of different kinds (e.g. Info) or +;; bookmarks that are marked or unmarked. +;; +;; Finally, you can easily define your own sorting commands and sort +;; orders. See macro `bmkp-define-sort-command' and the +;; documentation for option `bmkp-sort-comparer'. (Bookmark+ uses +;; option `bmkp-sort-comparer'; it *ignores* vanilla Emacs option +;; `bookmark-sort-flag'.) +;; +;; Of particular note is that you can interactively define commands +;; that sort by a given list of tags - you use keys `T s' (command +;; `bmkp-define-tags-sort-command') to do that. You are prompted for +;; the tags to sort by. Bookmarks are sorted first according to +;; whether they are tagged with the first tag, then the second tag, +;; and so on. Otherwise, sorting is by bookmark name. +;; +;; The tags you specify are used, in order, in the name of the new +;; command. For example, if you enter tags `alpha', `beta', and +;; `gamma', in that order, then the sorting command created is +;; `bmkp-bmenu-sort-alpha-beta-gamma'. The new command is saved in +;; your bookmark commands file (`bmkp-bmenu-commands-file'). +;; +;; Note that because you can add a new tag to all bookmarks that have +;; some given set of tags, you can use that single (new) tag to +;; represent the entire tag set. Sorting by that tag is then the +;; same as sorting by the tag set. You can of course use overlapping +;; sets in the composite sort command. You can, for example, sort +;; first according to tag `tag1', which represents the set of tags +;; `alpha', `beta', `gamma', `delta', and then sort according to tag +;; `tag2', which represents the set of tags `beta', `delta'. +;; +;; See also (@> "Use Bookmark+ with Icicles") - the same technique is +;; used in `Icicles' for sorting bookmarks as completion candidates. + +;;(@* "Bookmarks for Specific Files or Buffers") +;; ** Bookmarks for Specific Files or Buffers ** +;; +;; A bookmark typically records a position or a region in a file or +;; buffer. Sometimes you are interested in accessing or examining +;; only the bookmarks for particular files or buffers. For example, +;; you might want to navigate among the bookmarks for the current +;; buffer. Or you might want to search the regions recorded in the +;; bookmarks for a particular file. +;; +;; For a bookmark, the recorded file and buffer name differ in that +;; the file name is absolute. Bookmarks for buffer `foo.el' include +;; all files named `foo.el', whereas bookmarks for file +;; `/project1/lisp/foo.el' include only the files in that one +;; directory. +;; +;; Another important difference is that when multiple buffers visit +;; different files that have the same relative file name (i.e., in +;; different directories), Emacs makes the buffer names unique by +;; appending `' as needed, where `N' is 2, 3,... When you create +;; a bookmark, the current buffer name is recorded as the bookmark's +;; buffer. If the current buffer is not visiting a file, then the +;; bookmark created is a non-file bookmark. In that case, to use the +;; bookmark later you must have a buffer of the same name +;; (e.g. `foo.el<2>'). +;; +;; Bookmark+ provides commands to handle these different use cases: +;; specific files and specific buffers. The keys bound to these +;; commands use `f' for file and `b' for buffer. In the +;; bookmark-list display, the following keys affect the bookmarks for +;; a particular file or buffer whose name you provide (with +;; completion). +;; +;; * `= f M' and `= b M' - mark +;; * `= f S' and `= b S' - show (only) +;; +;; For navigation, the following keys jump to bookmarks for +;; particular files or buffers. (Use `C-x 4 j' for other-window.) +;; +;; * `C-x j ,,' - current buffer +;; * `C-x j = f' and `C-x j = b' - specified file(s) or buffer(s) +;; +;; For the `=' keys you are prompted for one or more file names or +;; buffer names. +;; +;; Finally, because the bookmarks in the current buffer can be of +;; particular interest, `C-x x ,' opens the bookmark-list display for +;; only those bookmarks. (`,' stands generally for "this-buffer" in +;; Bookmark+ key bindings.) + +;;(@* "Cycling, Navigation List") +;; ** "Cycling, Navigation List" ** +;; +;; Using completion to jump to a bookmark is handy. It lets you +;; choose a bookmark by its name and gives you direct ("random") +;; access to it. +;; +;; Sometimes, however, you don't much care what a bookmark is named, +;; and you want to cycle quickly among relatively few, related +;; bookmarks. Obviously, the smaller the number of bookmarks in the +;; set, the more convenient cycling is - with many bookmarks cycling +;; can become tedious. +;; +;; An analogy: If your TV has lots of channels, then the channel +;; up/down buttons on the remote control are not so useful: 32, 33, +;; 34, ..., 79! Unless the channel you want happens to be near the +;; current channel, cycling around a huge ring of channels is not the +;; way to go. And just because your TV receives lots of channels +;; does not mean that you watch them all or that you are equally +;; interested in them all. +;; +;; Some TV remote controls have a feature that mitigates this +;; problem. You can define a ring of favorite channels, and there +;; are two additional buttons that let you cycle forward and backward +;; around the ring, skipping the channels in between. The number of +;; favorites is relatively small, so cycling is not tedious. More +;; importantly, all of the channels in the ring are ones you are +;; interested in. +;; +;; Extend this idea to allow for assigning different sets of channels +;; to the favorites ring at different times: choose the ring you want +;; at any time: sports, music, films, science, art, history, and so +;; on. Add the possibility of sorting those sets in various ways, to +;; further facilitate cycling, and you arrive at the idea behind the +;; Bookmark+ navigation list. +;; +;; Another analogy is a music playlist. You can use Bookmark+ as a +;; simple music player by bookmarking music files. Similarly, you +;; can use Bookmark+ to create slideshows by bookmarking image files. +;; Cycle the navigation list to move through the slide show. +;; +;; If you use MS Windows, you can take advantage of your existing +;; file associations to open your bookmarks using the appropriate +;; program - no need to define a new bookmark type and handler. See +;; (@> "Bookmarking Files That You Cannot Visit with Emacs"). +;; +;; Note: The default value of option `bmkp-use-region' is `t', not +;; `cycling-too', which means that when you cycle to a bookmark its +;; recorded region (if any) is not activated. This is probably what +;; you want most of the time. Cycling is a repetitive action, and if +;; you cycle to a bookmark with no recorded region then an already +;; active region is just extended. Customize the value to +;; `cycling-too' if you prefer that behavior. +;; +;; +;;(@* "The Bookmark Navigation List") +;; *** "The Bookmark Navigation List *** +;; +;; Bookmark+ is all about letting you define and manipulate sets of +;; bookmarks. When a bookmark set can be used for cycling (as well +;; as jumping) it is called the "navigation list" or "navlist", for +;; short. +;; +;; In other words, Bookmark+ lets you cycle among any set of +;; bookmarks. When you cycle, it is the set that currently +;; constitutes the navigation list that is cycled. +;; +;; Here are two ways to define the navigation list: +;; +;; * `C-x x :' (`bmkp-choose-navlist-of-type') - As the set of all +;; bookmarks of a certain type (`any' or empty input means use all +;; bookmarks). +;; +;; * `C-x x B' (`bmkp-choose-navlist-from-bookmark-list') - As the +;; set of all bookmarks corresponding to a bookmark-list bookmark, +;; that is the bookmarks corresponding to a given recorded state of +;; buffer `*Bookmark List*'. +;; +;; Each of these lets you choose a set of bookmarks using completion. +;; For `C-x x :' you are prompted for the type of bookmark +;; (e.g. `dired'). +;; +;; For `C-x x B' you are prompted for the name of a bookmark-list +;; bookmark that you created. But you can also choose the candidate +;; `CURRENT *Bookmark List*' to capture the bookmarks that would be +;; shown currently in the `*Bookmark List*' (even if the list is not +;; displayed now). See (@> "State-Restoring Commands and Bookmarks") +;; for information about bookmark-list bookmarks. +;; +;; If you do not define the navigation list before you start cycling, +;; it is automatically defined as follows: +;; +;; * If you cycle using a current-file/buffer cycling key such as +;; `C-x x down' (see (@> "Cycling in the Current File/Buffer")) +;; then the bookmarks in the current file or buffer are used as the +;; navlist. +;; +;; * Otherwise, a snapshot is taken of the the bookmarks currently in +;; the global bookmark list (the value of variable +;; `bookmark-alist') as the navlist. +;; +;; However the navlist is defined, it is important to remember this: +;; it is a static snapshot of some set of bookmarks taken at a given +;; time. Subsequent changes to the bookmark list that was copied are +;; not reflected in the navlist. If you add a bookmark it will not +;; be among those cycled. But see also +;; (@> "Cycling Dynamic Sets of Bookmarks") for how to cycle dynamic +;; sets. +;; +;; You can update the navlist at any time by taking another snapshot +;; of the same bookmark list you used for the last snapshot. For the +;; global bookmark list just use `C-x x : RET'. (You can of course +;; bind that action to a shorter key sequence if you like.) +;; +;; Besides cycling among the bookmarks of the navlist (see next), +;; once you have defined the navigation list you can use `C-x j N' or +;; `C-x 4 j N' to jump to its bookmarks, as mentioned in section +;; (@> "Different Types of Jump Commands"). +;; +;; Note that just because you might have used `C-x x B' to define the +;; navlist using a particular bookmark-list bookmark or the current +;; `*Bookmark List*' state, that does not mean that the `*Bookmark +;; List*' state at any given time necessarily reflects the navlist +;; bookmarks. The two are separate. You can, however, open the +;; `*Bookmark List*' so that it reflects the bookmarks currently in +;; the navigation list, using `C-x x N' (`bmkp-navlist-bmenu-list'). +;; +;; +;;(@* "Cycling the Navigation List") +;; *** "Cycling the Navigation List" *** +;; +;; So you choose a navigation list. How do you then cycle among its +;; bookmarks? +;; +;; Commands `bmkp-next-bookmark' and `bmkp-previous-bookmark' cycle +;; to the next and previous bookmark in the navigation list (with +;; wraparound). (There are also other-window versions of these +;; commands.) +;; +;; You can bind these to any keys you like, but it's obviously better +;; to choose keys that are easily repeatable (e.g. by holding them +;; pressed). Some people who are used to using MS Visual Studio +;; might want to use `f2' and `S-f2' to cycle forward and backward. +;; +;; Bookmark+ does not define such key bindings, but you can. What it +;; does is define repeatable keys on the `bookmark-map' keymap, which +;; by default has prefix `C-x x'. To do this it binds similar +;; commands that can be repeated by simply repeating the key-sequence +;; suffix. These are the (default) keys: +;; +;; Forward: `C-x x f', `C-x x C-f', `C-x x right' +;; Backward: `C-x x b', `C-x x C-b', `C-x x left' +;; +;; (If you use an Emacs version prior to Emacs 22, you cannot use +;; this prefix-key repeatable feature.) +;; +;; In addition, if you use MS Windows then you can invoke the Windows +;; `Open' action on each bookmark when you cycle, to act on its file +;; using the program associated with the file type. This lets you +;; play music or display images in a playlist or slideshow fashion. +;; These are the keys to do that: +;; +;; Forward: `C-x x next' (PageDown key) +;; Backward: `C-x x prior' (PageUp key) +;; +;; Being able to cycle among an arbitrary set of bookmarks is the +;; most important feature of Bookmark+ cycling. The other important +;; feature is that if the navigation list is defined by `*Bookmark +;; List*' then the characteristics of that bookmark display are +;; respected for navigation. Only the bookmarks visible in +;; `*Bookmark List*' are included, and the `*Bookmark List*' sort +;; order is used for navigation. +;; +;; So you can not only choose any set of bookmarks for cycling at any +;; given time, you can also cycle among them in an order you choose. +;; For example, if in the bookmark list display (`C-x x e' or `C-x r +;; l') you show only those file bookmarks that belong to a given +;; project, and you have them sorted by file size, then cycling moves +;; among only those files, in file-size order. +;; +;; This is a main reason you will want to define bookmark-list +;; bookmarks, which record a specific set of bookmarks and their sort +;; order: to later choose given sets in different contexts for +;; cycling. +;; +;; +;;(@* "Cycling Dynamic Sets of Bookmarks") +;; *** "Cycling Dynamic Sets of Bookmarks" *** +;; +;; The fact that the navlist is a static snapshot is a useful +;; feature, but sometimes you might want to cycle among a particular +;; dynamic set of bookmarks, that is, to have cycling take changes to +;; the bookmark set into account automatically. For that, Bookmark+ +;; provides separate cycling commands for most types of bookmark. +;; +;; By default, these different kinds of cycling commands are not +;; bound to any keys, with the exception of the commands for cycling +;; the current fle or buffer. This exception includes cycling all +;; bookmarks for the current file/buffer +;; (see (@> "Cycling in the Current File/Buffer") +;; and cycling only the highlighted bookmarks for the current +;; file/buffer (see (@> "Using Highlighted Bookmarks")). Keys `C-x x +;; down' and `C-x x C-down' are defined for these two kinds of +;; current-buffer cycling. +;; +;; If you often want to cycle among the bookmarks of some other +;; particular kind (e.g. only the autonamed bookmarks), then you can +;; bind the relevant commands +;; (e.g. `bmkp-next-autonamed-bookmark-repeat', +;; `bmkp-previous-autonamed-bookmark-repeat', or their other-window +;; versions) to handy keys. Otherwise, you can just use the cycling +;; commands without binding them. +;; +;; +;;(@* "Cycling in the Current File/Buffer") +;; *** "Cycling in the Current File/Buffer" *** +;; +;; You can navigate the bookmarks in the current file or buffer by +;; cycling as well as jumping. It is convenient to have dedicated +;; keys for this, separate from the keys to cycle the navigation +;; list. The following keys are defined, corresponding to commands +;; `bmkp-next-bookmark-this-file/buffer-repeat' and +;; `bmkp-previous-bookmark-this-file/buffer-repeat': +;; +;; Next: `C-x x n', `C-x x C-n', `C-x x down' +;; Previous: `C-x x p', `C-x x C-p', `C-x x up' +;; +;; Starting with Emacs 23.3 (Emacs fix for bug #6256), you can also +;; use the mouse wheel to cycle: `C-x x' then just rotate the wheel. +;; +;; Again, you can bind any keys you want to these commands +;; (e.g. `f2', `S-f2'). If you do not need to use a prefix key, then +;; bind commands `bmkp-next-bookmark-this-file/buffer' and +;; `bmkp-previous-bookmark-this-file/buffer' (no -repeat). +;; +;; You can also cycle among just the highlighted bookmarks in the +;; current file or buffer - see (@> "Using Highlighted Bookmarks"). +;; +;; Cycling among bookmarks for the current file or buffer (whether +;; all or only the highlighted ones) is dynamic: the current set of +;; bookmarks is cycled, not a static snapshot taken at some point in +;; past. The navlist is automatically updated to the current dynamic +;; set each time you cycle. This is different from the usual cycling +;; of the navlist, where it is taken as a static snapshot - +;; see (@> "The Bookmark Navigation List"). +;; +;; By default, you cycle among the bookmarks for the current file or +;; buffer in order of their buffer positions, top to bottom. If you +;; want a different order, you can customize option +;; `bmkp-this-file/buffer-cycle-sort-comparer'. +;; +;; Alternatively, you can use `C-x x ,' to display the `*Bookmark +;; List*' with only the current file/buffer's bookmarks, sort them +;; there, and then use `C-x x B' to set the navigation list to +;; `CURRENT *Bookmark List*'. In that case, you use the navlist +;; cycling keys (e.g. `C-x x f', not `C-x x n'), and the cycled set +;; is a static snapshot. +;; +;; Note that the keys mentioned here cycle bookmarks for the current +;; file if visiting a file, or the current buffer otherwise. There +;; are also commands (unbound to keys) for cycling bookmarks for the +;; current file only or the current buffer only. +;; +;; The bookmarks for the current buffer are those that were created +;; in a buffer of exactly the same name. If one buffer visits a file +;; `foo.el', and another buffer visits a different file of the same +;; name (i.e., in a different directory), the second buffer will have +;; the name `foo.el<2>'. The buffer name is recorded when you create +;; a bookmark. If you later use same-buffer cycling then the +;; bookmarks cycled are only those created with the same buffer name +;; as the current buffer. +;; +;; This is the reason why the `*-file/buffer*' commands are bound to +;; keys. They are usually what you want. They try first to work +;; with bookmarks for the same file as the current buffer, if it is +;; visiting a file. + +;;(@* "Autonamed Bookmarks - Easy Come Easy Go") +;; ** "Autonamed Bookmarks - Easy Come Easy Go" ** +;; +;; Sometimes it is convenient to quickly create and delete bookmarks +;; whose names you don't really care about. That is the purpose of +;; "autonamed" bookmarks. An autonamed bookmark has a simple name +;; provided automatically, and it does not record any region +;; information - it records only a position. An autonamed bookmark +;; is nevertheless an ordinary, persistent bookmark. +;; +;; `C-x x RET' creates a bookmark at point without prompting you for +;; the name. It is named using the current buffer name preceded by +;; the position in the buffer. For example, the default name of the +;; autonamed bookmark in buffer `foo.el' at position 58356 is +;; `000058356 foo.el'. +;; +;; When you jump to any bookmark, the actual destination can differ +;; from the recorded position, because the buffer text might have +;; changed. In that case, the position you jump to has been +;; automatically relocated using the recorded bookmark context (some +;; buffer text surrounding the original position). +;; +;; If option `bmkp-save-new-location-flag' is non-`nil' then, after +;; jumping, the recorded position of the bookmark is automatically +;; updated to reflect the new location jumped to. This is true for +;; any bookmark. +;; +;; In the case of an autonamed bookmark, the bookmark name typically +;; reflects the recorded position when you create it. And when you +;; jump to it, both the name and the recorded position are updated to +;; reflect the jump destination. So jumping to an autonamed bookmark +;; keeps its persistent record in sync with the buffer location. +;; +;; You will thus notice that the names of autonamed bookmarks can +;; change as you visit them (e.g. cycling). The bookmarks are +;; automatically repositioned following their recorded contexts, and +;; their names reflect that repositioning. +;; +;; It is only when you jump to a bookmark that it is repositioned +;; this way, and only if needed. It is normal that some bookmarks +;; become somewhat out of sync with their original positions as you +;; edit the text in the buffer. In addition, if you highlight +;; bookmarks then you will notice the highlighting move as you edit +;; nearby text. The recorded bookmark has not changed, but its +;; highlight has moved. The highlight moves more or less as if it +;; were an Emacs marker. When you jump to the bookmark and it is thus +;; updated, the highlight moves back to the recorded position, +;; adjusted perhaps to fit the recorded context. +;; +;; `C-x x RET' is `bmkp-toggle-autonamed-bookmark-set/delete', and it +;; does double duty. If an autonamed bookmark is under the cursor, +;; then `C-x x RET' deletes it. Easy creation, easy deletion. +;; Because of this toggle behavior, there is at most one autonamed +;; bookmark at any given buffer position. +;; +;; `C-x x RET' has a third use: With a prefix argument, it prompts +;; you to confirm the deletion of *ALL* autonamed bookmarks for the +;; current buffer. +;; +;; (You can also use `C-x x delete' (that's the `delete' key), bound +;; to `bmkp-delete-bookmarks', to delete individual bookmarks under +;; the cursor or all bookmarks in the buffer. This is not limited to +;; autonamed bookmarks.) +;; +;; In addition to `C-x x RET', you can create autonamed bookmarks +;; using these commands: +;; +;; * `bmkp-set-autonamed-bookmark-at-line' - At a line beginning +;; * `bmkp-set-autonamed-regexp-buffer' - At buffer matches +;; * `bmkp-set-autonamed-regexp-region' - At region matches +;; * `bmkp-occur-create-autonamed-bookmarks' (`C-c b' in `*Occur*') - +;; At `occur' and `multi-occur' hits +;; +;; Autonamed bookmarks are normal bookmarks. In particular, they are +;; persisted. If you do not care to persist them, you can ensure +;; that they are automatically deleted by adding +;; `bmkp-delete-autonamed-this-buffer-no-confirm' to +;; `kill-buffer-hook' and `bmkp-delete-autonamed-no-confirm' to +;; `kill-emacs-hook': +;; +;; (add-hook 'kill-buffer-hook +;; 'bmkp-delete-autonamed-this-buffer-no-confirm) +;; (add-hook 'kill-emacs-hook +;; 'bmkp-delete-autonamed-no-confirm) +;; +;; You can customize the format of autonamed bookmarks using options +;; `bmkp-autoname-bookmark-function' and `bmkp-autoname-format'. +;; +;; For example, if you want autonamed bookmarks to show the line and +;; column numbers, in the form `L,C ', where +;; is a sequence of decimal digits and is the buffer name, +;; then you can use a function such as this as the value of +;; `bmkp-autoname-bookmark-function': +;; +;; (defun my-auto-l+c-name (position) +;; "Return a name for POSITION that uses line & column numbers." +;; (let ((line (line-number-at-pos position)) +;; (col (save-excursion +;; (goto-char position) (current-column)))) +;; (format "L%d,C%d %s" col line (buffer-name)))) +;; +;; To enable Bookmark+ to recognize such bookmarks as autonamed, you +;; would then set `bmkp-autoname-format' to the format specification +;; "^L[0-9]+,C[0-9]+ %B", to match their names. Here, the `%B' is a +;; Bookmark+ format specifier that corresponds to the buffer name. +;; +;; Recognizing the buffer name in an autonamed bookmark is important +;; or commands that act only on autonamed bookmarks for a specific +;; buffer. That includes commands `bmkp-autonamed-this-buffer-jump' +;; and `bmkp-delete-all-autonamed-for-this-buffer'. +;; +;; You use the special format specifier `%B' for the buffer name, +;; instead of just `%s', because the format can have multiple `%' +;; sequences, and the buffer name could be anywhere in the bookmark +;; name. Depending on the buffer, the buffer name could thus be +;; confused with other text in the bookmark name, unless you use `%B' +;; to show where it is. You can use just `%s' for it if there is no +;; risk of ambiguity. (Use `%s' in `bmkp-autoname-bookmark-function' +;; to insert the buffer name.) + +;;(@* "Temporary Bookmarks") +;; ** Temporary Bookmarks ** +;; +;; Autonamed bookmarks are easy-come-easy-go in the sense that `C-x x +;; RET' either sets (creates) one or deletes the one under the +;; cursor. But what about temporary bookmarks in general? What if +;; you want only bookmarks that are temporary, that is, not saved to +;; disk? Or what if you want certain kinds of bookmarks to always be +;; temporary? Or what if you want to toggle whether particular +;; bookmarks get saved automatically? +;; +;; +;;(@* "Temporary Bookmarking Mode") +;; *** Temporary Bookmarking Mode *** +;; +;; As always, you can control whether the bookmarks in the current +;; bookmark list are saved automatically using option +;; `bookmark-save-flag'. Remember that you can toggle this option +;; using command `bmkp-toggle-saving-bookmark-file' (bound to `M-~' +;; in the bookmark-list buffer). Remember too that you can at any +;; time change the set of available bookmarks (the bookmark list), +;; which means also changing the set of bookmarks that are +;; susceptible to being saved. +;; +;; You could, for example: +;; +;; 1. Use `C-x x 0' (`bmkp-empty-file') to create a new, empty +;; bookmark file. +;; +;; 2. Use `C-x x L' (`bmkp-switch-bookmark-file-create') to switch to +;; using that new, empty bookmark file. +;; +;; 3. Use `M-x bmkp-toggle-saving-bookmark-file' to turn off +;; auto-saving bookmarks to disk. +;; +;; This is essentially what the minor-mode toggle command +;; `bmkp-temporary-bookmarking-mode' does. When in this minor mode, +;; bookmarks that you create are stored on the new bookmark list, +;; which is not automatically saved to disk. If you do not +;; explicitly save it yourself then the bookmarks are lost when your +;; Emacs session ends - they are only temporary. +;; +;; This command is bound to `M-L' in the bookmark-list display buffer +;; (`*Bookmark List*'). The suffix `L' indicates that this has to do +;; with loading a bookmark file. See (@> "Using Multiple Bookmark Files"). +;; +;; In the bookmark-list display, temporary bookmarking mode is +;; indicated in the mode line by `TEMPORARY Bookmarking' in place of +;; `Bookmarks' as the mode name. +;; +;; +;;(@* "Making Bookmarks Temporary") +;; *** Making Bookmarks Temporary *** +;; +;; Instead of simply switching to a temporary bookmark list, so that +;; *all* bookmarking is only temporary, you more often want to have +;; some bookmarks be temporary while still ensuring that others get +;; saved. Or you temporarily want all new bookmarks that you create +;; and all bookmarks that you update to be temporary, without +;; affecting other, unchanged bookmarks. +;; +;; You can control this at the level of individual bookmarks, types +;; of bookmarks, or all bookmarks whenever they are set (created or +;; updated). +;; +;; * At the individual-bookmark level, commands +;; `bmkp-make-bookmark-temporary' and `bmkp-make-bookmark-savable' +;; prompt you for a bookmark name and then set its +;; temporary/savable status. Command +;; `bmkp-toggle-temporary-bookmark' combines these commands, +;; toggling the status for a given bookmark. +;; +;; In the bookmark list, this toggle is bound to `C-M-X'. There +;; are also commands in the bookmark-list display to toggle the +;; temporary/savable status of the marked bookmarks (`M-X'), to +;; mark the temporary bookmarks (`X M'), and to show only the +;; temporary bookmarks (`X S'). +;; +;; * At the bookmark-type level, you can customize user option +;; `bmkp-autotemp-bookmark-predicates'. It is a list of bookmark +;; predicates - typically type predicates - that define which +;; bookmarks are automatically made temporary whenever they are +;; set. +;; +;; The default value includes the type predicates for autonamed +;; bookmarks: `bmkp-autonamed-bookmark-p' and +;; `bmkp-autonamed-this-buffer-bookmark-p'. This means that (only) +;; autonamed bookmarks are made temporary whenever they are created +;; or updated. +;; +;; The doc string for the option lists the predefined bookmark type +;; predicates, but you can use any bookmark predicates. +;; +;; * Finally, you can toggle whether *all* bookmarks become temporary +;; whenever they are created or updated, using command +;; `bmkp-toggle-autotemp-on-set', which is bound globally to `C-x x +;; x'. +;; +;; You can delete all such temporary bookmarks from the current +;; bookmark list using command `bmkp-delete-all-temporary-bookmarks' +;; (or by using `X M' to mark them in the bookmark-list display and +;; then hitting `D' to delete thems). +;; +;; In the bookmark-list display (buffer `*Bookmark List*'), temporary +;; bookmarks are indicated with the mark `X' in the same column where +;; the annotation mark `a' would otherwise appear. + +;;(@* "Automatic Bookmarking") +;; ** Automatic Bookmarking ** +;; +;; You might find automatic bookmarking useful. The idea is that +;; Emacs sets a bookmark for you automatically. +;; +;; Bookmark+ can do this either when you perform some action (besides +;; explicitly bookmarking) or whenever you are idle for a given +;; period of time (option `bmkp-automatic-bookmark-mode-delay'). +;; +;; +;;(@* "Automatic Bookmarking Using a Hook") +;; *** Automatic Bookmarking Using a Hook *** +;; +;; To automatically set a bookmark whenever some hook is run, put +;; function `bmkp-set-automatic-bookmark' on the hook. For example, +;; to set a bookmark at a definition jumped to whenever you use +;; Imenu, you can do this: +;; +;; (add-hook 'imenu-after-jump-hook #'bmkp-set-automatic-bookmark) +;; +;; The bookmark is an autonamed bookmark (see +;; (@> "Autonamed Bookmarks - Easy Come Easy Go")). +;; +;; +;;(@* "Automatic Idle-Period Bookmarking") +;; *** Automatic Idle-Period Bookmarking *** +;; +;; Automatic idle-period bookmarking creates bookmarks at spots where +;; you spend some time (idly). It uses +;; `bmkp-set-automatic-bookmark', so the bookmarks created are +;; autonamed (see (@> "Autonamed Bookmarks - Easy Come Easy Go")). +;; +;; How many such bookmarks would you want? And how close together? +;; Bookmark+ tries to provide some user options that let you get the +;; behavior you want. Except for +;; `bmkp-automatic-bookmark-mode-delay' they apply to +;; `bmkp-set-automatic-bookmark', so they affect both idle-period +;; bookmarking and automatic bookmarking on a hook. +;; +;; In general, you probably don't want such bookmarks to be created +;; too often or too close together. You probably don't care about +;; the names of the bookmarks created, and you don't want to be +;; interrupted to have to name them. You probably want automatic +;; idle-period bookmarking to be per-buffer, but you might sometimes +;; want to turn it on or off for all buffers. You might want more +;; than one automatic bookmark on a given line, but probably not. +;; Finally, you might or might not want such bookmarks to be +;; temporary (current session only) or highlighted. +;; +;; Mode `bmkp-automatic-bookmark-mode' is a local minor mode, which +;; means that it is buffer-specific. The command of the same name +;; turns the mode on and off. When the mode is on, the minor-mode +;; indicator ("lighter") `Auto-Bmk' is shown in the mode line for the +;; buffer. You can customize this indicator (removing it, if you +;; like), using option `bmkp-automatic-bookmark-mode-lighter'. +;; +;; Command `bmkp-global-automatic-bookmark-mode' turns on the mode in +;; all buffers, that is, it is global, not local. Regardless of +;; whether you use the mode locally or globally, a bookmark is +;; created automatically only in the current buffer. That is, a +;; buffer must be current (selected) for an automatic bookmark to be +;; created there - it's not enough that the mode be enabled in the +;; buffer. +;; +;; Option `bmkp-automatic-bookmark-set-function' defines the +;; bookmark-setting function. By default, its value is +;; `bmkp-set-autonamed-bookmark-at-line', which sets an autonamed +;; bookmark at (the beginning of) the current line. If you want +;; bookmarks to be created automatically then you typically want them +;; to be autonamed, both because the name is unimportant and because +;; setting an autonamed bookmark requires no interaction on your +;; part. But you can use any setting function you like as the option +;; value. (You can always rename an autonamed bookmark later, if you +;; want to keep it and give it a meaningful name.) +;; +;; Option `bmkp-automatic-bookmark-min-distance' is the minimum +;; number of characters between automatic bookmark positions. If the +;; cursor is currently closer to some existing automatically created +;; bookmark, then no automatic bookmark is set at point. If you set +;; this to `nil' then there is no limit on how close the bookmarks +;; can be. (But there is only one autonamed bookmark at any given +;; position.) +;; +;; If you want automatically created bookmarks to be temporary (not +;; saved to your bookmark file), then customize option +;; `bmkp-autotemp-bookmark-predicates' so that it includes the kind +;; of bookmarks that are set by +;; `bmkp-automatic-bookmark-set-function'. For example, if automatic +;; bookmarking sets autonamed bookmarks, then +;; `bmkp-autotemp-bookmark-predicates' should include +;; `bmkp-autonamed-bookmark-p' or +;; `bmkp-autonamed-this-buffer-bookmark-p' (it includes both of these +;; by default). Remember that you can toggle whether a given +;; bookmark is temporary or savable, using `M-X' in the bookmark-list +;; display (buffer `*Bookmark List*'). +;; +;; If you want the bookmarks to be automatically highlighted, then +;; customize option `bmkp-auto-light-when-set' to highlight bookmarks +;; of the appropriate kind. For example, to highlight autonamed +;; bookmarks set it to `autonamed-bookmark'. +;; +;; NOTE: If you use Emacs 20, then by default +;; `bmkp-automatic-bookmark-mode' is global rather than local. The +;; doc string tells you how to make it local instead. If you use +;; Emacs 21, then `bmkp-automatic-bookmark-mode' is local but there +;; is no global mode, `bmkp-global-automatic-bookmark-mode'. This is +;; because Emacs 21 does not support `define-globalized-minor-mode'. +;; +;; +;;(@* "Automatic Info Bookmarking") +;; *** Automatic Info Bookmarking *** +;; +;; If you enable global minor mode `bmkp-info-auto-bookmark-mode', +;; each Info node you visit is bookmarked automatically, using the +;; default bookmark name, which is the Info manual name plus the node +;; name. For example, node `Lisp Data Types' in the Elisp manual +;; gives you a bookmark named `(elisp) Lisp Data Types'. +;; +;; With the mode enabled, when you visit an Info node an existing +;; bookmark with the same name is always updated. If no such +;; bookmark exists then a new one is created, provided option +;; `bmkp-info-auto-type' has value `create-or-replace'. If it has +;; value `update-only' then no new bookmark is created. The default +;; option value is `update-only'. You can toggle the value using +;; command `bmkp-toggle-info-auto-type'. +;; +;; With `bmkp-info-auto-bookmark-mode' enabled, even if you have +;; created Info bookmarks with the default names manually, they are +;; updated automatically. In particular, updating a bookmark +;; increments the recorded number of visits to the Info node and the +;; time of the last visit. +;; +;; You can sort bookmarks in the bookmark-list display by the time of +;; last visit, using `s d', or by the number of visits, using `s v'. +;; +;; This gives you an easy way to see which parts of the manuals you +;; have visited most recently and how much you have visited them. +;; Showing only Info bookmarks gives you the effect of a persistent +;; mini-manual of just the visited Info nodes. Turn the mode off +;; anytime you do not want to record Info visits. +;; +;; Also useful in this context, though not related to bookmarking, is +;; the ability to save your Info history persistently, so links to +;; visited nodes are shown using a different face. This makes it +;; easy to see which parts of a manual you have already looked at. +;; (And checking a bookmark to a visited node shows you how much you +;; have visited it.) +;; +;; If you use library `info+.el' then you have this complementary +;; ability save your Info history list persistently. Just enable +;; minor mode `Info-persist-history-mode'. + +;;(@* "Highlighting Bookmark Locations") +;; ** Highlighting Bookmark Locations ** +;; +;; You can highlight the location (destination) of a bookmark. For +;; this feature you need library `bookmark+-lit.el' in addition to +;; the other Bookmark+ libraries. +;; +;; You might never want to highlight a bookmark, or you might want to +;; highlight most or even all bookmarks, or your use of highlighting +;; might fall somewhere between. It depends on what kind of +;; bookmarks you have and how you use them. Bookmark+ lets you +;; choose. By default, no bookmarks are highlighted. + +;;(@* "Defining How to Highlight") +;; ** Defining How to Highlight ** +;; +;; By default, autonamed bookmarks are highlighted differently from +;; non-autonamed bookmarks. Bookmark highlighting uses a style and a +;; face. The available styles are these: +;; +;; * Region - Highlight the region, if a region bookmark +;; * Line - Highlight line of the bookmark position +;; * Position - Highlight character at bookmark position +;; * Line Beginning - Highlight first character on line +;; * Left Fringe - Highlight only the left fringe +;; * Left Fringe + Line - Highlight the left fringe and the line +;; * Right Fringe - Highlight only the right fringe +;; * Right Fringe + Line - Highlight the right fringe and the line +;; +;; You can customize the default styles and faces to use for +;; autonamed and non-autonamed bookmarks. You can also customize the +;; fringe bitmaps to use. +;; +;; * `bmkp-light-autonamed' (face) +;; * `bmkp-light-non-autonamed' (face) +;; * `bmkp-light-autonamed-region' (face) +;; * `bmkp-light-non-autonamed-region' (face) +;; * `bmkp-light-style-autonamed' (option) +;; * `bmkp-light-style-non-autonamed' (option) +;; * `bmkp-light-style-autonamed-region' (option) +;; * `bmkp-light-style-non-autonamed-region' (option) +;; * `bmkp-light-left-fringe-bitmap' (option) +;; * `bmkp-light-right-fringe-bitmap' (option) +;; +;; Note: A region, position, or line highlight acts more or less like +;; an Emacs marker: it moves with the surrounding text. As you edit +;; the text in the buffer, the highlighted location can thus become +;; out of sync with the recorded position. This is normal. When you +;; jump to the bookmark, its highlight is automatically repositioned +;; to the recorded location, possibly adjusted according to the +;; surrounding context. +;; +;; In addition to the default highlighting, which you can customize, +;; you can set the highlighting for individual bookmarks and +;; particular sets of bookmarks (overriding their default +;; highlighting). These individual settings are saved as part of the +;; bookmarks themselves. +;; +;; In the bookmark list display (buffer `*Bookmark List*'): +;; +;; * `H +' - Set the highlighting for this line's bookmark +;; * `H > +' - Set the highlighting for the marked bookmarks +;; +;; Globally, you can use `M-x bmkp-set-lighting-for-bookmark' to set +;; the highlighting for a given bookmark. +;; +;; Each of these commands prompts you (with completion) for the style +;; and face to set, as well as for a condition that controls whether +;; to highlight. Each of these is optional - just hit `RET' (empty +;; input) at its prompt to skip setting it. +;; +;; The condition is an Emacs-Lisp sexp that is evaluated whenever an +;; attempt is made to highlight the bookmark. Any resulting value +;; except `:no-light' highlights the bookmark. The sexp can refer to +;; the variables `this-bookmark' and `this-bookmark-name', whose +;; values are the bookmark to be highlighted and its name, +;; respectively. +;; +;; So, for example, if you wanted to be prompted each time before +;; highlighting a certain bookmark you might set its highlighting +;; condition to a sexp such as this: +;; +;; (or (y-or-n-p (format "Highlight `%s' " this-bookmark-name)) +;; :no-light) +;; +;; If you hit `n' at the prompt then `:no-light' is returned and the +;; bookmark is not highlighted. +;; +;; In the bookmark-list display, a pink-background, one-character +;; highlight is used next to each bookmark that has a highlight +;; override wrt the default. You can see what that override setting +;; is by using `C-u C-h RET' - look for the `lighting' entry in the +;; bookmark definition. +;; +;; +;;(@* "Highlighting On Demand") +;; *** Highlighting On Demand *** +;; +;; You can highlight or unhighlight a bookmark or a set of bookmarks +;; on demand. +;; +;; In the bookmark list (buffer `*Bookmark List*'): +;; +;; * `H H', `H U' - Highlight, unhighlight this line's bookmark +;; +;; * `H > H', `H > U' - Highlight, unhighlight the marked bookmarks +;; +;; Globally: +;; +;; * `C-x x C-u' - Unhighlight a highlighted bookmark at +;; point or on the same line (in that order) +;; +;; * `C-x x h', `C-x x u' - Highlight, unhighlight a bookmark in the +;; current buffer (with completion). +;; +;; * `C-x x H', `C-x x U' - Highlight, unhighlight bookmarks: +;; +;; With plain `C-u': all bookmarks +;; +;; With `C-u C-u': navigation-list bookmarks +;; +;; Otherwise, bookmarks in current buffer: +;; No prefix arg: all bookmarks +;; Prefix arg > 0: autonamed bookmarks +;; < 0: non-autonamed bookmarks +;; +;; The default bookmark for `C-x x u' is the same bookmark that is +;; unhighlighted by `C-x x C-u': a (highlighted) bookmark at point +;; (preferably) or on the same line. The latter key binding just +;; saves you having to hit `RET' to pick the default. +;; +;; When you use `C-x x h', you can use a prefix argument to override +;; both the default highlighting and any highlighting that is +;; recorded for the bookmark itself. You are prompted for the style +;; or face to use: +;; +;; * Negative arg: prompted for style +;; * Non-negative arg: prompted for face +;; * Plain `C-u': prompted for style and face +;; +;; +;;(@* "Highlighting Automatically") +;; *** Highlighting Automatically *** +;; +;; You can also highlight automatically, whenever you set (create) a +;; bookmark or jump to one. This is controlled by these options: +;; +;; * `bmkp-auto-light-when-set' +;; * `bmkp-auto-light-when-jump' +;; +;; You can choose any of these values for either option: +;; +;; * Autonamed bookmark +;; * Non-autonamed bookmark +;; * Any bookmark +;; * Autonamed bookmarks in buffer +;; * Non-autonamed bookmarks in buffer +;; * All bookmarks in buffer +;; * None (no automatic highlighting) - the default +;; +;; The first three values highlight only the bookmark being set or +;; jumped to. +;; +;; Be aware that, depending on the setting, highlighting can take a +;; while. + +;;(@* "Using Highlighted Bookmarks") +;; ** Using Highlighted Bookmarks ** +;; +;; Once you have highlighted bookmarks, what can you do with them? +;; Obviously, the highlighting can help you distinguish and find +;; bookmarks visually. But highlighting also serves as yet another +;; way to define sets: the highlighted vs unhighlighted bookmarks. +;; +;; Any command that operates on a set of bookmarks can be applied to +;; one or the other of these two sets. Bookmark+ defines only a few +;; such operations, but you can easily define others. +;; +;; In addition to such specific commands, you can also apply general +;; operations to the highlighted or unhighlighted bookmarks, using +;; the bookmark-list display (`*Bookmark List*'). `H S' shows only +;; the bookmarks that are currently highlighted, and `H M' marks +;; them. You can then perform any of the available bookmark-list +;; operations on them. +;; +;; Globally, you can use these keys: +;; +;; * `C-x x =' - List the bookmarks that are +;; highlighted at point. With a +;; prefix arg, show the full data. +;; +;; * `C-x j h', `C-x 4 j h' - Jump to a highlighted bookmark. +;; Only highlighted bookmarks are +;; completion candidates. +;; +;; * `C-x x C-down', `C-x x C-up' - Cycle to the next and previous +;; highlighted bookmark. + +;;(@* "Bookmark Links") +;; ** Bookmark Links ** +;; +;; You can use command `bmkp-insert-bookmark-link' to create links in +;; any Emacs text that jump to particular bookmarks when you follow +;; them (by hitting `RET' or clicking `mouse-2'). If you hit `?' or +;; double-click `mouse-1' on such a bookmark link then the bookmark +;; is described, showing the same information as `C-h M' +;; (`bmkp-describe-bookmark'). +;; +;; You are prompted for the bookmark to link. If the region is +;; active and nonempty then the link is put on its text. Otherwise, +;; you are prompted for the link text, which is inserted. The +;; default link text is the bookmark name in this case. +;; +;; The bookmark linked can be of any type. +;; +;; This simple feature lets you easily create "launching pads" for +;; different sets of bookmarks: buffers or files that consist of +;; bookmark links and any other text you like. This gives you yet +;; another way to organize bookmarks (and so also the files, +;; directories, etc. that they target). +;; +;; If you also use library `font-lock+.el' then the links appear with +;; face `link', even in a font-locked buffer. (Library +;; `font-lock+.el' just provides this feature of allowing +;; non-font-lock highlighting in a font-locked buffer. See +;; https://lists.gnu.org/archive/html/emacs-devel/2014-08/msg00540.html.) +;; +;; The links you create this way are not persistent, but you can of +;; course re-create them using Lisp. +;; +;; +;;(@* "Org Mode Links that Jump To Bookmarks") +;; *** Org Mode Links that Jump To Bookmarks *** +;; +;; You can also easily define Org-mode links that jump to bookmarks. +;; These links are persistent. Again, the bookmark linked can be of +;; any type. +;; +;; You can use the standard Org command `org-store-link' (`C-c l') in +;; buffer `*Bookmark List*' to store a link to the bookmark at point. +;; (This is also item `Store Org Link' in the mouse-3 popup menu.) +;; +;; Outside buffer `*Bookmark List*' you can use command +;; `bmkp-store-org-link' to store a link to any bookmark. You are +;; prompted for the bookmark name. You can even enter the name of a +;; bookmark that does not yet exist. (This is also item `Store Org +;; Link To...' on menu `Bookmarks'.) +;; +;; If you use a numeric prefix arg with either command then the +;; bookmark link stored will be for jumping to the bookmark in the +;; same window. Without a numeric prefix arg, the link will use +;; another window. (Org mode defines other behaviors for non-numeric +;; prefix args, such as `C-u C-u'.) +;; +;; As usual, to insert a bookmark link, you use command +;; `org-insert-link'. Enter the name of the target bookmark at the +;; prompt. In Org mode you can use the usual Org key bindings to +;; follow the link. In any mode you can use standard Org command +;; `org-open-at-point-global' (not bound to a key by default). + +;;(@* "Bookmark Menus") +;; ** Bookmark Menus ** +;; +;; Two menu-bar menus for Bookmark+ have already been mentioned: +;; +;; * Menu `Bookmark+', for the bookmark-list display (buffer +;; `*Bookmark List*'). +;; +;; * Menu `Bookmarks', which is typically a submenu of the menu-bar +;; `Edit' menu (available also with vanilla Emacs but enhanced by +;; Bookmark+). +;; +;; Access to bookmarks for the currently visited file or current +;; buffer is available as a `Bookmarks Here' submenu of the +;; major-mode menu-bar menu in modes Info and Buffer-Menu, if option +;; `bmkp-add-bookmarks-here-menu-flag' is non-`nil'. +;; +;; The menu items let you cycle among bookmarks in the current +;; file/buffer or access the bookmark-list display for only those +;; bookmarks. +;; +;; If you use library Dired+ then the same access is available in +;; Dired mode on menu-bar menu `Dir' > `Bookmark' > `Here'. +;; +;; If you use library Imenu+ then the same access is available in an +;; Imenu submenu `Bookmarks Here'. In this case there are also menu +;; items to jump to each bookmark in the file/buffer. For Imenu, +;; display of the menu is controlled by option +;; `imenup-show-bookmarks-flag'. + +;;(@* "Use Bookmark+ with Icicles") +;; ** Use Bookmark+ with Icicles ** +;; +;; `Icicles' (https://www.emacswiki.org/emacs/Icicles) enhances your +;; use of Bookmark+ in several ways. +;; +;; When jumping to a bookmark, you can narrow the completion +;; candidates to bookmarks of a particular type (e.g. Info, using +;; `C-M-i'; remote, using `C-M-@'; region, using `C-M-r'). You can +;; narrow again (and again), to another bookmark type, to get the +;; intersection (e.g. remote Info bookmarks that define a region). +;; +;; You can also narrow against different bookmark-name patterns +;; (e.g. regexps) - so-called "progressive completion". And take the +;; complement (e.g., bookmarks whose names do not match +;; `foo.*2010.*bar'). (This is not special to bookmarks; it is +;; standard `Icicles' practice.) +;; +;; In Icicle mode, several of the Bookmark+ keys are remapped to +;; corresponding `Icicles' multi-commands. A bookmark jump key thus +;; becomes a bookmarks browser. For example, `C-x j d' browses among +;; any number of Dired bookmarks. +;; +;; A single key can set a bookmark or visit bookmarks. This key is +;; whatever command `bmkp-bookmark-set-confirm-overwrite' would +;; normally be bound to - e.g. `C-x r m'. A prefix arg controls what +;; it does. If negative (`M--'), jump to (browse) bookmarks. +;; Otherwise, set a bookmark using +;; `bmkp-bookmark-set-confirm-overwrite', as follows: +;; +;; * No prefix arg: Prompt for the bookmark name. The candidates are +;; bookmarks in the current buffer (or all bookmarks if there are +;; none in the current buffer). +;; +;; * (Non-negative) numeric prefix arg: No prompt. Use the buffer +;; name plus the text of the region (if active) or the current line +;; as the bookmark name. Quickest way to set a bookmark. +;; +;; * Plain `C-u': Prompt for name, no bookmark overwrite. +;; +;; During completion of a bookmark name, many features of the +;; bookmark-list display (see (@> "The Bookmark List Display")) are +;; available on the fly. Buffer `*Completions*' acts like a dynamic +;; version of `*Bookmark List*': +;; +;; * Candidates are highlighted in the `*Completions*' window +;; according to their bookmark type. +;; +;; * Candidates are `Icicles' multi-completions with up to three +;; parts: +;; +;; a. the bookmark name +;; b. the bookmark file or buffer name +;; c. any tags +;; +;; You can match any or all of the parts. For example, you can +;; match bookmarks that have tags by typing this regexp: +;; +;; C-M-j . * C-M-j S-TAB +;; +;; Each `C-M-j' inserts `^G\n', which is `icicle-list-join-string', +;; the string used to join the parts. This regexp says, "match the +;; completion candidates that have all three parts (two join +;; strings)", hence some tags. +;; +;; You can turn off the use of multi-completion candidates for +;; subsequent commands, so only bookmark names are used, by hitting +;; `M-m' in the minibuffer. You can think of this as similar to +;; using `M-t' in `*Bookmark List*' to toggle showing file names. +;; You can make not showing files and tags the default behavior by +;; customizing `icicle-show-multi-completion-flag'. +;; +;; * You can sort completion candidates using the Bookmark+ sort +;; orders. Use `C-,' to cycle among sort orders. +;; +;; * You can use `Icicles' candidate-help keys (`C-M-RET', +;; `C-M-down', etc.) to get detailed information about the current +;; bookmark candidate. `C-u C-M-RET' shows the complete, internal +;; info defining the bookmark. And without doing anything, summary +;; info about the current candidate is available in the mode line +;; of buffer `*Completions*'. +;; +;; * You can use `Icicles' candidate-action keys (`C-RET', +;; `C-mouse-2', `C-down', etc.) to visit any number of bookmarks. +;; For example, holding down `C-down' cycles among the current +;; bookmark candidates, opening each in turn. +;; +;; * You can use `S-delete' to delete the bookmark named by the +;; current candidate. You can delete any number of bookmarks this +;; way, during a single invocation of a bookmark command. +;; +;; * You can define `Icicles' sets of bookmarks, persistent or not, +;; and act on their members in various ways. +;; +;; During file-name completion, you can do any of the following on +;; the fly: +;; +;; * Jump to one or more file bookmarks, using `C-x m'. +;; +;; * Create one or more autofile bookmarks, using `C-x a a'. +;; +;; * Add tags to one or more files or directories (autofile +;; bookmarks), using `C-x a +'. +;; +;; * Remove tags from one or more files or directories (autofile +;; bookmarks), using `C-x a -'. +;; +;; There are 25 Icicles commands for searching bookmark destinations! +;; The most general is `icicle-search-bookmark'. Others let you +;; search specific kinds of bookmarks, or bookmarks having various +;; combinations of tags. +;; +;; During Icicles search (of anything, not just a bookmark +;; destination), you can save sets of completion candidates, which +;; means sets of search hits, as bookmarks. And Icicles lets you use +;; set operations (complement, union, intersection, difference etc.) +;; on the current set of search hits. +;; +;; When you "jump" to an Icicles search-hits bookmark, its recorded +;; search hits are restored to Icicles search as completion +;; candidates, either replacing the current candidates or adding to +;; them. +;; +;; You can thus save and later return to different sets of search +;; results using different bookmarks. You can "jump" to an Icicles +;; search-hits bookmark during any Icicles search, whether you search +;; a file, a buffer, multiple files, or multiple buffers. + +;;(@* "Bookmark Compatibility with Vanilla Emacs (`bookmark.el')") +;; ** Bookmark Compatibility with Vanilla Emacs (`bookmark.el') ** +;; +;; Bookmark+ is generally compatible with GNU Emacs versions 20 and +;; later. You can use bookmarks with Bookmark+ regardless of whether +;; they were created using Bookmark+ or vanilla Emacs (i.e., library +;; `bookmark.el'). +;; +;; But for best results, if you have bookmarks that you created using +;; Bookmark+ then use Bookmark+, not vanilla Emacs, to access them. +;; This section provides details. +;; +;; Set user option `bmkp-propertize-bookmark-names-flag', depending +;; on your usage scenario (the default is `t' for Emacs 21 and later, +;; `nil' for Emacs 20): +;; +;; 1. Set it to `nil' if you will often be going back and forth +;; between using Bookmark+ and using vanilla Emacs. (Do this also +;; if you use Emacs 20.) +;; +;; 2. Set it to non-`nil' if you instead always use only Bookmark+ +;; (with Emacs 21 or later), or you use vanilla Emacs only to jump +;; to bookmarks but never to update or create bookmarks. +;; +;; #1 is VERY IMPORTANT. You can lose data if you do not respect it. +;; +;; The reason for rule #1 is this: When the option is non-`nil' +;; Bookmark+ writes bookmarks to your bookmark file in a format that +;; can be read and used by vanilla Emacs (21 and later) but which +;; vanilla Emacs then saves as unreadable. If the option value is +;; `nil' there is no such problem. +;; +;; #2 is not a requirement. It is just a good idea, to be able to +;; take better advantage of Bookmark+. If you set the option to +;; `nil' then you cannot use multiple bookmarks that have the same +;; name. Vanilla Emacs does not make good use of such critters, but +;; Bookmark+ does. Having multiple bookmarks with the same name is +;; particularly useful for autofiles. It means you can have +;; different autofiles in different directories but with the same +;; name. See (@> "Autofile Bookmarks"). +;; +;; Here is what happens when `bmkp-propertize-bookmark-names-flag' is +;; non-nil: +;; +;; Besides its name, which is what you see and use most of the time, +;; a bookmark contains other information such as the target location, +;; textual context hints, and last access time. Non-`nil' +;; `bmkp-propertize-bookmark-names-flag' has no effect on vanilla +;; Emacs, but it causes Bookmark+ to put the full bookmark +;; information on the bookmark name as a text property. +;; +;; The name thus encapsulates all of the information contained in the +;; full bookmark of which it is part. Knowing the name is then +;; enough to know everything about the bookmark. Part of the +;; bookmark (its name) refers to the whole of it. In Lisp this +;; self-reference is implemented using circular structures. +;; +;; When Bookmark+ saves such circular structures to your bookmark +;; file, if the option is non-`nil' then it takes care to do so in +;; such a way that they can be read in again when your bookmark file +;; is loaded. In Lisp terms, it binds `print-circle' to non-`nil' +;; when it writes your bookmarks. If the option value is `nil' then +;; the circularity (self-reference) is removed before your bookmarks +;; are saved. Either way, the file is readable. +;; +;; Vanilla Emacs (21 and later) has no problem reading your bookmark +;; file if it contains such circular structures. But if you then use +;; it to save the file again, the Lisp code it writes has invalid +;; Lisp `read' syntax (because it does not remove the circularity but +;; it also does not bind `print-circle' to non-`nil'). +;; +;; If that happens, the result is a bookmark file that is UNREADABLE. +;; It cannot be loaded into either vanilla Emacs or Bookmark+. If +;; you do not have an uncorrupted backup version of the file to +;; revert to, then you will need to edit it by hand to clean it up. +;; +;; So do not let that happen to you! For best results use only +;; Bookmark+ to access bookmarks created using Bookmark+. +;; +;; If you must use vanilla Emacs with your bookmarks, then make sure +;; they are not saved by Bookmark+ with the option non-`nil': Using +;; Bookmark+, set the option to `nil' and then save the file. +;; +;; That is: +;; +;; 1. `M-x set-variable bmkp-propertize-bookmark-names-flag nil', +;; to stop using propertized bookmark names. +;; 2. `C-x x e' or `C-x r l', to display the bookmark list. +;; 3. `g', to refresh the display. +;; 4. `S', to save the bookmark list. +;; 5. `M-x bmkp-save-menu-list-state', to save the display state. +;; +;; Then you can use your bookmark file with vanilla Emacs (but +;; without the possibility of having multiple bookmarks with the same +;; name). +;; +;; Note that when the option value is non-`nil', propertized bookmark +;; names are saved not only to your bookmark file but also to any +;; full snapshots you create of the bookmark-list display state using +;; command `bmkp-bmenu-define-full-snapshot-command' (`C-c C-C', aka +;; `C-c C-S-c'). See (@> "State-Restoring Commands and Bookmarks"). + +;;(@* "New Bookmark Structure") +;; ** New Bookmark Structure ** +;; +;; The bookmark data structure, variable `bookmark-alist', has been +;; enhanced to support new bookmark types. For a description of this +;; enhanced structure, use `C-h v bookmark-alist'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;; You need not load this file. It contains only documentation. + +(provide 'bookmark+-doc) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-doc.el ends here + diff --git a/lisp/bookmark+-key.el b/lisp/bookmark+-key.el new file mode 100644 index 00000000..bc8e7079 --- /dev/null +++ b/lisp/bookmark+-key.el @@ -0,0 +1,1474 @@ +;;; bookmark+-key.el --- Bookmark+ key and menu bindings. +;; +;; Filename: bookmark+-key.el +;; Description: Bookmark+ key and menu bindings. +;; Author: Drew Adams +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2010-2022, Drew Adams, all rights reserved. +;; Created: Fri Apr 1 15:34:50 2011 (-0700) +;; Last-Updated: Fri Jan 14 12:49:18 2022 (-0800) +;; By: dradams +;; Update #: 980 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-key.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+, placeholders, annotations, search, info, url, eww, w3m, gnus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) library +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit.el' - (optional) code for highlighting bookmarks +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (bmenu) +;; `bookmark+-1.el' - other (non-bmenu) required code +;; `bookmark+-key.el' - key and menu bindings (this file) +;; +;; `bookmark+-doc.el' - documentation (comment-only file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you have library +;; `bookmark+-doc.el' in your `load-path'.) +;; +;; +;; User options defined here: +;; +;; `bmkp-add-bookmarks-here-menu-flag', +;; `bmkp-bookmark-map-prefix-key', `bmkp-jump-map-prefix-key', +;; `bmkp-jump-other-window-map-prefix-key'. +;; +;; Non-interactive functions defined here: +;; +;; `bmkp-bookmark-data-from-record', +;; `bmkp-bookmark-name-from-record', +;; `bmkp-exists-bookmark-satisfying-p', +;; `bmkp-exists-this-file/buffer-bookmarks-p', +;; `bmkp-set-map-prefix-key', `bookmark-name-from-full-record', +;; `bookmark-name-from-record'. +;; +;; Internal variables defined here: +;; +;; `bmkp-annotate-map', `bmkp-annotate-menu', `bmkp-here-menu', +;; `bmkp-bookmarks-here-menu-command-entries', +;; `bmkp-find-file-menu', `bmkp-highlight-menu', `bmkp-jump-map', +;; `bmkp-jump-menu', `bmkp-jump-other-window-map', +;; `bmkp-jump-tags-menu', `bmkp-set-map', `bmkp-tags-map', +;; `bmkp-tags-menu'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; *This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;;;;;;;;;;;;;;;;;;;; + +(eval-when-compile + (or (condition-case nil + (load-library "bookmark+-mac") ; Use load-library to ensure latest .elc. + (error nil)) + (require 'bookmark+-mac))) ; Require, so can load separately if not on `load-path'. +;; bmkp-menu-bar-make-toggle + +(eval-when-compile (require 'cl)) ;; case + +;;;;;;;;;;;;;;;;;;;;;;; + +;; Quiet the byte-compiler + +(defvar bmkp-bmenu-buffer) ; In `bookmark+.el' +(defvar grep-mode-map) + + +;; Prefix keys. +;; +;; These two maps are always on `bookmark-map', wherever it is: `bmkp-set-map', `bmkp-tags-map'. +;; +(defun bmkp-set-map-prefix-key (pref-keys-option keys) + "Set prefix key option SYMBOL to key-sequence VALUE." + (set pref-keys-option keys) + (let* ((g-map (current-global-map)) + (b-map (case pref-keys-option + (bmkp-bookmark-map-prefix-keys 'bookmark-map) + (bmkp-jump-map-prefix-keys 'bmkp-jump-map) + (bmkp-jump-other-window-map-prefix-keys 'bmkp-jump-other-window-map)))) + (dolist (key (where-is-internal b-map g-map)) + (define-key g-map key nil)) + (dolist (key keys) + (define-key g-map key b-map)))) + +(defcustom bmkp-bookmark-map-prefix-keys (list (kbd "C-x x")) + "Prefix keys for `bookmark-map' in `current-global-map'. +Each value of the list is a prefix key bound to keymap `bookmark-map'." + :type (if (> emacs-major-version 21) + '(repeat (key-sequence :tag "Key" :value [ignore])) + '(repeat (restricted-sexp + :tag "Key" + :match-alternatives ((lambda (x) (or (stringp x) (vectorp x)))) + :value [ignore]))) + :set 'bmkp-set-map-prefix-key + :group 'bookmark-plus) + +(defcustom bmkp-jump-map-prefix-keys (list (kbd "C-x j")) + "Prefix keys for `bmkp-jump-map' in `current-global-map'. +Each value of the list is a prefix key bound to keymap +`bmkp-jump-map'." + :type (if (> emacs-major-version 21) + '(repeat (key-sequence :tag "Key" :value [ignore])) + '(repeat (restricted-sexp + :tag "Key" + :match-alternatives ((lambda (x) (or (stringp x) (vectorp x)))) + :value [ignore]))) + :set 'bmkp-set-map-prefix-key + :group 'bookmark-plus) + +(defcustom bmkp-jump-other-window-map-prefix-keys (list (kbd "C-x 4 j")) + "Prefix keys for `bmkp-jump-other-window-map' in `current-global-map'. +Each value of the list is a prefix key bound to keymap +`bmkp-jump-other-window-map'." + :type (if (> emacs-major-version 21) + '(repeat (key-sequence :tag "Key" :value [ignore])) + '(repeat (restricted-sexp + :tag "Key" + :match-alternatives ((lambda (x) (or (stringp x) (vectorp x)))) + :value [ignore]))) + :set 'bmkp-set-map-prefix-key + :group 'bookmark-plus) + +(defcustom bmkp-add-bookmarks-here-menu-flag nil + "Non-nil means add a `Bookmarks Here' menu to some menu-bar menus. +The menu is added only if there are in fact bookmarks for the current +buffer or file. The default value is nil because checking whether +there are such bookmarks can take a little time." + :type 'boolean :group 'bookmark-plus) + + + +;; Some general Renamings. +;; +;; 1. Fix incompatibility introduced by gratuitous Emacs name change. +;; +(cond ((and (fboundp 'bookmark-name-from-record) (not (fboundp 'bookmark-name-from-full-record))) + (defalias 'bookmark-name-from-full-record 'bookmark-name-from-record)) + ((and (fboundp 'bookmark-name-from-full-record) (not (fboundp 'bookmark-name-from-record))) + (defalias 'bookmark-name-from-record 'bookmark-name-from-full-record))) + +;; 2. The vanilla name of the first is misleading, as it returns only the cdr of the record. +;; The second is for consistency. +;; +(defalias 'bmkp-bookmark-data-from-record 'bookmark-get-bookmark-record) +(defalias 'bmkp-bookmark-name-from-record 'bookmark-name-from-full-record) + + +;; Quiet the byte-compiler +(defvar bmkp-bmenu-menubar-menu) ; In `bookmark+-bmu.el'. +(defvar bmkp-bmenu-toggle-menu) ; In `bookmark+-bmu.el'. +(defvar bmkp-crosshairs-flag) ; In `bookmark+-1.el'. +(defvar bmkp-eww-replace-keys-flag) ; In `bookmark+-1.el' (Emacs 25+). +(defvar bmkp-prompt-for-tags-flag) ; In `bookmark+-1.el'. +(defvar bmkp-save-new-location-flag) ; In `bookmark+-1.el'. +(defvar diredp-bookmark-menu) ; In `dired+.el'. +(defvar eww-mode-map) ; In `eww.el' (Emacs 24.4+). +(defvar gnus-summary-mode-map) ; In `gnus-sum.el'. +(defvar Info-mode-map) ; In `info.el'. +(defvar Info-mode-menu) ; In `info.el'. +(defvar Man-mode-map) ; In `man.el'. +(defvar mouse-wheel-down-event) ; In `mwheel.el'. +(defvar mouse-wheel-up-event) ; In `mwheel.el'. +(defvar w3m-minor-mode-map) ; In `w3m.el'. +(defvar w3m-mode-map) ; In `w3m.el'. +(defvar woman-menu) ; In `woman.el'. +(defvar woman-mode-map) ; In `woman.el'. + +;;(@* "Keymaps") +;;; Keymaps ---------------------------------------------------------- + +;; `help-map' +(define-key help-map "M" 'bmkp-describe-bookmark) + +;; `bookmark-map' + +;; (define-key ctl-x-map "x" bookmark-map) +;; (define-key ctl-x-map "xj" 'bookmark-jump-other-window) ; `C-x x j' (also `C-x 4 j j') +(define-key ctl-x-map "rK" 'bmkp-set-desktop-bookmark) ; `C-x r K' (also `C-x x K', `C-x x c K') + +(define-key bookmark-map "0" 'bmkp-empty-file) ; `C-x x 0' +(define-key bookmark-map "2" 'bmkp-clone-bookmark) ; `C-x x 2' +(define-key bookmark-map "5" 'bookmark-jump-other-frame) ; `C-x x 5' +(define-key bookmark-map "B" 'bmkp-choose-navlist-from-bookmark-list) ; `C-x x B' +;; `e' is `edit-bookmarks' (aka `bookmark-bmenu-list', from vanilla Emacs. +(define-key bookmark-map "E" 'bmkp-edit-bookmark-record) ; `C-x x E' +;; The original `bookmark-insert-location' in `bookmark.el' was `f'. +(define-key bookmark-map "I" 'bookmark-insert-location) ; `C-x x I' +(define-key bookmark-map "\C-j" 'bmkp-jump-to-list) ; `C-x x C-j' +(define-key bookmark-map "K" 'bmkp-set-desktop-bookmark) ; `C-x x K' (also `C-x r K', `C-x x c K') +(define-key bookmark-map "L" 'bmkp-switch-bookmark-file-create) ; `C-x x L' +(define-key bookmark-map "\C-l" 'bmkp-switch-to-bookmark-file-this-file/buffer) ; `C-x x C-l' +(define-key bookmark-map "m" 'bmkp-bookmark-set-confirm-overwrite) ; `C-x x m' +(define-key bookmark-map "N" 'bmkp-navlist-bmenu-list) ; `C-x x N' +(define-key bookmark-map "o" 'bookmark-jump-other-window) ; `C-x x o' (also `C-x 4 j j') +(define-key bookmark-map "q" 'bookmark-jump-other-window) ; `C-x x q' (also `C-x 4 j j') +(define-key bookmark-map "r" 'bmkp-edit-bookmark-name-and-location) ; `C-x x r' +(define-key bookmark-map "\C-s" 'bmkp-save-bookmarks-this-file/buffer) ; `C-x x C-s' +(define-key bookmark-map "\M-w" 'bmkp-set-snippet-bookmark) ; `C-x x M-w' (also `C-x x c M-w') +(define-key bookmark-map "x" 'bmkp-toggle-autotemp-on-set) ; `C-x x x' +(define-key bookmark-map "y" 'bmkp-set-bookmark-file-bookmark) ; `C-x x y' +(when (featurep 'bookmark+-lit) + (define-key bookmark-map "h" 'bmkp-light-bookmark-this-buffer) ; `C-x x h' + (define-key bookmark-map "H" 'bmkp-light-bookmarks) ; `C-x x H' + (define-key bookmark-map "u" 'bmkp-unlight-bookmark-this-buffer) ; `C-x x u' + (define-key bookmark-map "U" 'bmkp-unlight-bookmarks) ; `C-x x U' + (define-key bookmark-map "\C-u" 'bmkp-unlight-bookmark-here) ; `C-x x C-u' + (define-key bookmark-map "=" 'bmkp-bookmarks-lighted-at-point)) ; `C-x x =' +(define-key bookmark-map "," 'bmkp-this-file/buffer-bmenu-list) ; `C-x x ,' +(define-key bookmark-map "?" 'bmkp-describe-bookmark-lighted-here) ; `C-x x ?' +(define-key bookmark-map ":" 'bmkp-choose-navlist-of-type) ; `C-x x :' +(define-key bookmark-map "\r" 'bmkp-toggle-autonamed-bookmark-set/delete) ; `C-x x RET' +(define-key bookmark-map [delete] 'bmkp-delete-bookmarks) ; `C-x x delete' + +(substitute-key-definition 'kill-line 'bmkp-delete-bookmarks ; `C-x x C-k', `C-x x deleteline' + bookmark-map (current-global-map)) +(define-key bookmark-map [deletechar] 'bmkp-delete-bookmarks) ; `C-x x deletechar' +;; For Mac Book: +(define-key bookmark-map [kp-delete] 'bmkp-delete-bookmarks) ; `C-x x kp-delete' + +;; If you use Emacs before Emacs 22, then you will want to bind the commands +;; whose names do *not* end in `-repeat' to keys that are easily repeatable. +;; For example, you might want to bind `bmkp-next-bookmark-this-file/buffer' +;; (not `bmkp-next-bookmark-this-file/buffer-repeat') to a key such as [f2]. +;; +(when (> emacs-major-version 21) + (define-key bookmark-map "n" 'bmkp-next-bookmark-this-file/buffer-repeat) ; `C-x x n' + (define-key bookmark-map "\C-n" 'bmkp-next-bookmark-this-file/buffer-repeat) ; `C-x x C-n' + (define-key bookmark-map [down] 'bmkp-next-bookmark-this-file/buffer-repeat) ; `C-x x down' + (put 'bmkp-next-bookmark-this-file/buffer-repeat :advertised-binding (kbd "C-x x ")) + + ;; This requires the fix for Emacs bug #6256, which is in Emacs 23.3 (presumably). + ;; For older Emacs versions you can bind the wheel event to `bmkp-next-bookmark-this-file/buffer' + ;; in the global map. IOW, prior to Emacs 23.3 a mouse event won't work with `repeat'. + (when (and (boundp 'mouse-wheel-up-event) + (or (> emacs-major-version 23) + (and (= emacs-major-version 23) (> emacs-minor-version 2)))) + (define-key bookmark-map (vector (list mouse-wheel-up-event)) + 'bmkp-next-bookmark-this-file/buffer-repeat)) ; `C-x x mouse-wheel-up' + (define-key bookmark-map "p" 'bmkp-previous-bookmark-this-file/buffer-repeat) ; `C-x x p' + (define-key bookmark-map "\C-p" 'bmkp-previous-bookmark-this-file/buffer-repeat) ; `C-x x C-p' + (define-key bookmark-map [up] 'bmkp-previous-bookmark-this-file/buffer-repeat) ; `C-x x up' + (put 'bmkp-previous-bookmark-this-file/buffer-repeat :advertised-binding (kbd "C-x x ")) + + ;; This requires the fix for Emacs bug #6256, which is in Emacs 23.3 (presumably). + ;; For older Emacs versions you can bind the wheel event to `bmkp-previous-bookmark-this-file/buffer' + ;; in the global map. IOW, prior to Emacs 23.3 a mouse event won't work with `repeat'. + (when (and (boundp 'mouse-wheel-down-event) + (or (> emacs-major-version 23) + (and (= emacs-major-version 23) (> emacs-minor-version 2)))) + (define-key bookmark-map (vector (list mouse-wheel-down-event)) + 'bmkp-previous-bookmark-this-file/buffer-repeat)) ; `C-x x mouse-wheel-down' + (define-key bookmark-map "f" 'bmkp-next-bookmark-repeat) ; `C-x x f' + (define-key bookmark-map "\C-f" 'bmkp-next-bookmark-repeat) ; `C-x x C-f' + (define-key bookmark-map [right] 'bmkp-next-bookmark-repeat) ; `C-x x right' + (put 'bmkp-next-bookmark-repeat :advertised-binding (kbd "C-x x ")) + (define-key bookmark-map "b" 'bmkp-previous-bookmark-repeat) ; `C-x x b' + (define-key bookmark-map "\C-b" 'bmkp-previous-bookmark-repeat) ; `C-x x C-b' + (define-key bookmark-map [left] 'bmkp-previous-bookmark-repeat) ; `C-x x left' + (put 'bmkp-previous-bookmark-repeat :advertised-binding (kbd "C-x x ")) + (define-key bookmark-map [next] 'bmkp-next-bookmark-w32-repeat) ; `C-x x next' + (define-key bookmark-map [prior] 'bmkp-previous-bookmark-w32-repeat) ; `C-x x prior' + (when (featurep 'bookmark+-lit) + (define-key bookmark-map [C-down] 'bmkp-next-lighted-this-buffer-repeat) ; `C-x x C-down' + (define-key bookmark-map [C-up] 'bmkp-previous-lighted-this-buffer-repeat))) ; `C-x x C-up' + + +;; `bmkp-annotate-map': prefix `C-x x a' + +(defvar bmkp-annotate-map nil "Keymap containing bindings for bookmark annotation commands.") + +(define-prefix-command 'bmkp-annotate-map) +(define-key bookmark-map "a" bmkp-annotate-map) ; `C-x x a' for annotate + +(define-key bmkp-annotate-map "a" 'bmkp-annotate-bookmark) ; `C-x x a a' +(define-key bmkp-annotate-map "b" 'bmkp-annotate-bookmark-this-file/buffer) ; `C-x x a b' +(define-key bmkp-annotate-map "B" 'bmkp-annotate-all-bookmarks-this-file/buffer) ; `C-x x a B' +(define-key bmkp-annotate-map "e" 'bookmark-edit-annotation) ; `C-x x a e' +(define-key bmkp-annotate-map "s" 'bookmark-show-annotation) ; `C-x x a s' +(define-key bmkp-annotate-map "S" 'bookmark-show-all-annotations) ; `C-x x a S' + + +;; `bmkp-set-map': prefix `C-x x c' + +(defvar bmkp-set-map nil "Keymap containing bindings for bookmark set commands.") + +(define-prefix-command 'bmkp-set-map) +(define-key bookmark-map "c" bmkp-set-map) ; `C-x x c' for create + +(define-key bmkp-set-map "a" 'bmkp-autofile-set) ; `C-x x c a' +(define-key bmkp-set-map "f" 'bmkp-file-target-set) ; `C-x x c f' +(define-key bmkp-set-map "F" 'bmkp-make-function-bookmark) ; `C-x x c F' +(define-key bmkp-set-map "K" 'bmkp-set-desktop-bookmark) ; `C-x x c K' +(define-key bmkp-set-map "\C-k" 'bmkp-wrap-bookmark-with-last-kbd-macro) ; `C-x x C-k' +(define-key bmkp-set-map "m" 'bmkp-bookmark-set-confirm-overwrite) ; `C-x x c m' +(define-key bmkp-set-map "M" 'bookmark-set) ; `C-x x c M' +(define-key bmkp-set-map "s" 'bmkp-set-sequence-bookmark) ; `C-x x c s' +(define-key bmkp-set-map "u" 'bmkp-url-target-set) ; `C-x x c u' +(define-key bmkp-set-map "\M-w" 'bmkp-set-snippet-bookmark) ; `C-x x c M-w' +(define-key bmkp-set-map "y" 'bmkp-set-bookmark-file-bookmark) ; `C-x x c y' +(define-key bmkp-set-map "\r" 'bmkp-toggle-autonamed-bookmark-set/delete) ; `C-x x c RET' + + +;; Add set commands to other keymaps: occur, compilation: `C-c C-b', `C-c C-M-b', `C-c C-M-B'. +;; See `dired+.el' for Dired bookmarking keys, which are different. + +(add-hook 'occur-mode-hook + (lambda () + (unless (lookup-key occur-mode-map "\C-c\C-b") + (define-key occur-mode-map "\C-c\C-b" 'bmkp-occur-target-set)) ; `C-c C-b' + (unless (lookup-key occur-mode-map "\C-c\C-\M-b") + (define-key occur-mode-map "\C-c\C-\M-b" 'bmkp-occur-target-set-all)) ; `C-c C-M-b' + (unless (lookup-key occur-mode-map [(control ?c) (control meta shift ?b)]) + (define-key occur-mode-map [(control ?c) (control meta shift ?b)] + 'bmkp-occur-create-autonamed-bookmarks)))) ; `C-c C-M-B' (aka `C-c C-M-S-b') + +(when (fboundp 'bmkp-compilation-target-set) ; Emacs 22+ + + (add-hook 'compilation-mode-hook + (lambda () + (unless (lookup-key compilation-mode-map "\C-c\C-b") + (define-key compilation-mode-map "\C-c\C-b" 'bmkp-compilation-target-set)) ; `C-c C-b' + (unless (lookup-key compilation-mode-map "\C-c\C-\M-b") ; `C-c C-M-b' + (define-key compilation-mode-map "\C-c\C-\M-b" 'bmkp-compilation-target-set-all)))) + + (when (fboundp 'compilation-minor-mode) ; Emacs 26+ + + (add-hook + 'grep-mode-hook + (lambda () + (unless (lookup-key grep-mode-map "\C-c\C-b") + (define-key grep-mode-map "\C-c\C-b" 'bmkp-compilation-target-set)) ; `C-c C-b' + (unless (lookup-key grep-mode-map "\C-c\C-\M-b") ; `C-c C-M-b' + (define-key grep-mode-map "\C-c\C-\M-b" 'bmkp-compilation-target-set-all)))) + + (add-hook + 'compilation-minor-mode-hook + (lambda () + (unless (lookup-key compilation-minor-mode-map "\C-c\C-b") + (define-key compilation-minor-mode-map "\C-c\C-b" 'bmkp-compilation-target-set)) ; `C-c C-b' + (unless (lookup-key compilation-minor-mode-map "\C-c\C-\M-b") ; `C-c C-M-b' + (define-key compilation-minor-mode-map "\C-c\C-\M-b" 'bmkp-compilation-target-set-all)))) + + (add-hook + 'compilation-shell-minor-mode-hook + (lambda () + (unless (lookup-key compilation-shell-minor-mode-map "\C-c\C-b") + (define-key compilation-shell-minor-mode-map + "\C-c\C-b" 'bmkp-compilation-target-set)) ; `C-c C-b' + (unless (lookup-key compilation-shell-minor-mode-map "\C-c\C-\M-b") ; `C-c C-M-b' + (define-key compilation-shell-minor-mode-map + "\C-c\C-\M-b" 'bmkp-compilation-target-set-all)))))) + + +;; `bmkp-tags-map': prefix `C-x x t' + +(defvar bmkp-tags-map nil "Keymap containing bindings for bookmark tag commands.") + +(define-prefix-command 'bmkp-tags-map) +(define-key bookmark-map "t" bmkp-tags-map) ; `C-x x t' for tags + +(define-key bmkp-tags-map "0" 'bmkp-remove-all-tags) ; `C-x x t 0' +(define-key bmkp-tags-map "+" nil) ; For Emacs 20 +(define-key bmkp-tags-map "+b" 'bmkp-add-tags) ; `C-x x t + b' +(define-key bmkp-tags-map "-b" 'bmkp-remove-tags) ; `C-x x t - b' +(define-key bmkp-tags-map "+a" 'bmkp-tag-a-file) ; `C-x x t + a' +(define-key bmkp-tags-map "-a" 'bmkp-untag-a-file) ; `C-x x t - a' +(define-key bmkp-tags-map "c" 'bmkp-copy-tags) ; `C-x x t c' +(define-key bmkp-tags-map "d" 'bmkp-remove-tags-from-all) ; `C-x x t d' +(define-key bmkp-tags-map "e" 'bmkp-edit-tags) ; `C-x x t e' +(define-key bmkp-tags-map "l" 'bmkp-list-all-tags) ; `C-x x t l' +(define-key bmkp-tags-map "p" 'bmkp-paste-add-tags) ; `C-x x t p' +(define-key bmkp-tags-map "q" 'bmkp-paste-replace-tags) ; `C-x x t q' +(define-key bmkp-tags-map "r" 'bmkp-rename-tag) ; `C-x x t r' +(define-key bmkp-tags-map "v" 'bmkp-set-tag-value) ; `C-x x t v' +(define-key bmkp-tags-map "V" 'bmkp-set-tag-value-for-navlist) ; `C-x x t V' +(define-key bmkp-tags-map "\M-w" 'bmkp-copy-tags) ; `C-x x t M-w' +(define-key bmkp-tags-map "\C-y" 'bmkp-paste-add-tags) ; `C-x x t C-y' + + +;; `bmkp-jump-map' and `bmkp-jump-other-window-map': prefixes `C-x j' and `C-x 4 j' + +(defvar bmkp-jump-map nil "Keymap containing bindings for bookmark jump commands.") + +(defvar bmkp-jump-other-window-map nil + "Keymap containing bindings for bookmark jump other-window commands.") + +(define-prefix-command 'bmkp-jump-map) +(define-prefix-command 'bmkp-jump-other-window-map) +;; (define-key ctl-x-map "j" bmkp-jump-map) +;; (define-key ctl-x-4-map "j" bmkp-jump-other-window-map) +(define-key bookmark-bmenu-mode-map "j" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "J" nil) ; For Emacs 20 +(define-key bookmark-bmenu-mode-map "J" bmkp-jump-map) +(define-key bookmark-bmenu-mode-map "j" bmkp-jump-other-window-map) +(define-key bookmark-bmenu-mode-map "j>" 'bmkp-bmenu-jump-to-marked) ; `j >' + +(define-key ctl-x-5-map "B" 'bookmark-jump-other-frame) ; `C-x j 5', `C-x 5 B' +(define-key bmkp-jump-map "5" 'bookmark-jump-other-frame ) ; `J 5' +(define-key bmkp-jump-map "." nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "." nil) ; For Emacs 20 +(define-key bmkp-jump-map ".d" 'bmkp-dired-this-dir-jump) ; `C-x j . d' +(define-key bmkp-jump-other-window-map ".d" 'bmkp-dired-this-dir-jump-other-window) ; `C-x 4 j . d' +(define-key bmkp-jump-map ".f" 'bmkp-file-this-dir-jump) ; `C-x j . f' +(define-key bmkp-jump-other-window-map ".f" 'bmkp-file-this-dir-jump-other-window) ; `C-x 4 j . f' + +(define-key bmkp-jump-map "," nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "," nil) ; For Emacs 20 +(define-key bmkp-jump-map ",," 'bmkp-this-buffer-jump) ; `C-x j , ,' +(define-key bmkp-jump-other-window-map ",," 'bmkp-this-buffer-jump-other-window) ; `C-x 4 j , ,' +(define-key bmkp-jump-map ",#" 'bmkp-autonamed-this-buffer-jump) ; `C-x j , #' +(define-key bmkp-jump-other-window-map ",#" + 'bmkp-autonamed-this-buffer-jump-other-window) ; `C-x 4 j , #' + +(define-key bmkp-jump-map "#" 'bmkp-autonamed-jump) ; `C-x j #' +(define-key bmkp-jump-other-window-map "#" 'bmkp-autonamed-jump-other-window) ; `C-x 4 j #' + +(define-key bmkp-jump-map "=" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "=" nil) ; For Emacs 20 +(define-key bmkp-jump-map "=b" 'bmkp-specific-buffers-jump) ; `C-x j = b' +(define-key bmkp-jump-other-window-map "=b" 'bmkp-specific-buffers-jump-other-window) ; `C-x 4 j = b' +(define-key bmkp-jump-map "=f" 'bmkp-specific-files-jump) ; `C-x j = f' +(define-key bmkp-jump-other-window-map "=f" 'bmkp-specific-files-jump-other-window) ; `C-x 4 j = f' + +(define-key bmkp-jump-map "a" 'bmkp-autofile-jump) ; `C-x j a' +(define-key bmkp-jump-other-window-map "a" 'bmkp-autofile-jump-other-window) ; `C-x 4 j a' +(define-key bmkp-jump-map "b" 'bmkp-non-file-jump) ; `C-x j b' +(define-key bmkp-jump-other-window-map "b" 'bmkp-non-file-jump-other-window) ; `C-x 4 j b' +(define-key bmkp-jump-map "B" 'bmkp-bookmark-list-jump) ; `C-x j B' +(define-key bmkp-jump-other-window-map "B" 'bmkp-bookmark-list-jump) ; SAME COMMAND: `C-x 4 j B' +(define-key bmkp-jump-map "d" 'bmkp-dired-jump) ; `C-x j d' +(define-key bmkp-jump-other-window-map "d" 'bmkp-dired-jump-other-window) ; `C-x 4 j d' + +(eval-after-load "eww" + '(when (> emacs-major-version 24) ; Emacs 25+ + (when bmkp-eww-replace-keys-flag + (bmkp-remap 'eww-add-bookmark 'bookmark-set eww-mode-map) + (bmkp-remap 'eww-list-bookmarks 'bookmark-bmenu-list eww-mode-map) + (bmkp-remap 'eww-next-bookmark 'bmkp-next-url-bookmark eww-mode-map) + (bmkp-remap 'eww-previous-bookmark 'bmkp-previous-url-bookmark eww-mode-map)) + (define-key bmkp-jump-map "e" 'bmkp-eww-jump) ; `C-x j e' + (define-key bmkp-jump-other-window-map "e" 'bmkp-eww-jump-other-window))) ; `C-x 4 j e' + +(define-key bmkp-jump-map "f" 'bmkp-file-jump) ; `C-x j f' +(define-key bmkp-jump-other-window-map "f" 'bmkp-file-jump-other-window) ; `C-x 4 j f' +(define-key bmkp-jump-map "\C-f" 'bmkp-find-file) ; `C-x j C-f' +(define-key bmkp-jump-other-window-map "\C-f" 'bmkp-find-file-other-window) ; `C-x 4 j C-f' +(define-key bmkp-jump-map "g" 'bmkp-gnus-jump) ; `C-x j g' +(define-key bmkp-jump-other-window-map "g" 'bmkp-gnus-jump-other-window) ; `C-x 4 j g' +(define-key bmkp-jump-map "h" 'bmkp-lighted-jump) ; `C-x j h' +(define-key bmkp-jump-other-window-map "h" 'bmkp-lighted-jump-other-window) ; `C-x 4 j h' +(define-key bmkp-jump-map "i" 'bmkp-info-jump) ; `C-x j i' +(define-key bmkp-jump-other-window-map "i" 'bmkp-info-jump-other-window) ; `C-x 4 j i' +(define-key bmkp-jump-map "\M-i" 'bmkp-image-jump) ; `C-x j M-i' +(define-key bmkp-jump-other-window-map "\M-i" 'bmkp-image-jump-other-window) ; `C-x 4 j M-i' +(define-key bmkp-jump-map "j" 'bookmark-jump) ; `C-x j j' +(put 'bookmark-jump :advertised-binding "\C-xjj") + +(define-key bmkp-jump-other-window-map "j" 'bookmark-jump-other-window) ; `C-x 4 j j' +(put 'bookmark-jump-other-window :advertised-binding "\C-x4jj") +(put 'jump-other :advertised-binding "\C-x4jj") + +(define-key bmkp-jump-map "\C-j" 'bmkp-jump-to-list) ; `C-x j C-j' +(define-key bmkp-jump-map "K" 'bmkp-desktop-jump) ; `C-x j K' +(define-key bmkp-jump-other-window-map "K" 'bmkp-desktop-jump) ; SAME COMMAND: `C-x 4 j K' +(define-key bmkp-jump-map "l" 'bmkp-local-file-jump) ; `C-x j l' +(define-key bmkp-jump-other-window-map "l" 'bmkp-local-file-jump-other-window) ; `C-x 4 j l' +(define-key bmkp-jump-map "m" 'bmkp-man-jump) ; `C-x j m' +(define-key bmkp-jump-other-window-map "m" 'bmkp-man-jump-other-window) ; `C-x 4 j m' +(define-key bmkp-jump-map "n" 'bmkp-remote-file-jump) ; `C-x j n' ("_n_etwork") +(define-key bmkp-jump-other-window-map "n" 'bmkp-remote-file-jump-other-window) ; `C-x 4 j n' +(define-key bmkp-jump-map "N" 'bmkp-jump-in-navlist) ; `C-x j N' +(define-key bmkp-jump-other-window-map "N" 'bmkp-jump-in-navlist-other-window) ; `C-x 4 j N' +(define-key bmkp-jump-map "r" 'bmkp-region-jump) ; `C-x j r' +(define-key bmkp-jump-other-window-map "r" 'bmkp-region-jump-other-window) ; `C-x 4 j r' +(define-key bmkp-jump-other-window-map "R" + 'bmkp-region-jump-narrow-indirect-other-window) ; `C-x 4 j R' + +(define-key bmkp-jump-map "t" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "t" nil) ; For Emacs 20 +(define-key bmkp-jump-map "t*" 'bmkp-all-tags-jump) ; `C-x j t *' +(define-key bmkp-jump-other-window-map "t*" 'bmkp-all-tags-jump-other-window) ; `C-x 4 j t *' +(define-key bmkp-jump-map "t+" 'bmkp-some-tags-jump) ; `C-x j t +' +(define-key bmkp-jump-other-window-map "t+" 'bmkp-some-tags-jump-other-window) ; `C-x 4 j t +' + +(define-key bmkp-jump-map "t%" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "t%" nil) ; For Emacs 20 +(define-key bmkp-jump-map "t%*" 'bmkp-all-tags-regexp-jump) ; `C-x j t % *' +(define-key bmkp-jump-other-window-map "t%*" + 'bmkp-all-tags-regexp-jump-other-window) ; `C-x 4 j t % *' +(define-key bmkp-jump-map "t%+" 'bmkp-some-tags-regexp-jump) ; `C-x j t % +' +(define-key bmkp-jump-other-window-map "t%+" + 'bmkp-some-tags-regexp-jump-other-window) ; `C-x 4 j t % +' + +(define-key bmkp-jump-map "t." nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "t." nil) ; For Emacs 20 +(define-key bmkp-jump-map "t.*" 'bmkp-file-this-dir-all-tags-jump) ; `C-x j t . *' +(define-key bmkp-jump-other-window-map "t.*" + 'bmkp-file-this-dir-all-tags-jump-other-window) ; `C-x 4 j t . *' +(define-key bmkp-jump-map "t.+" 'bmkp-file-this-dir-some-tags-jump) ; `C-x j t . +' +(define-key bmkp-jump-other-window-map "t.+" + 'bmkp-file-this-dir-some-tags-jump-other-window) ; `C-x 4 j t . +' + +(define-key bmkp-jump-map "t.%" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "t.%" nil) ; For Emacs 20 +(define-key bmkp-jump-map "t.%*" + 'bmkp-file-this-dir-all-tags-regexp-jump) ; `C-x j t . % *' +(define-key bmkp-jump-other-window-map "t.%*" + 'bmkp-file-this-dir-all-tags-regexp-jump-other-window) ; `C-x 4 j t . % *' +(define-key bmkp-jump-map "t.%+" + 'bmkp-file-this-dir-some-tags-regexp-jump) ; `C-x j t . % +' +(define-key bmkp-jump-other-window-map "t.%+" + 'bmkp-file-this-dir-some-tags-regexp-jump-other-window) ; `C-x 4 j t . % +' + + +(define-key bmkp-jump-map "ta" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "ta" nil) ; For Emacs 20 +(define-key bmkp-jump-map "ta*" 'bmkp-autofile-all-tags-jump) ; `C-x j t a *' +(define-key bmkp-jump-other-window-map "ta*" + 'bmkp-autofile-all-tags-jump-other-window) ; `C-x 4 j t a *' +(define-key bmkp-jump-map "ta+" 'bmkp-autofile-some-tags-jump) ; `C-x j t a +' +(define-key bmkp-jump-other-window-map "ta+" + 'bmkp-autofile-some-tags-jump-other-window) ; `C-x 4 j t a +' + +(define-key bmkp-jump-map "ta%" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "ta%" nil) ; For Emacs 20 +(define-key bmkp-jump-map "ta%*" 'bmkp-autofile-all-tags-regexp-jump) ; `C-x j t a % *' +(define-key bmkp-jump-other-window-map "ta%*" + 'bmkp-autofile-all-tags-regexp-jump-other-window) ; `C-x 4 j t a % *' +(define-key bmkp-jump-map "ta%+" 'bmkp-autofile-some-tags-regexp-jump) ; `C-x j t a % +' +(define-key bmkp-jump-other-window-map "ta%+" + 'bmkp-autofile-some-tags-regexp-jump-other-window) ; `C-x 4 j t a % +' + +(define-key bmkp-jump-map "tf" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "tf" nil) ; For Emacs 20 +(define-key bmkp-jump-map "tf*" 'bmkp-file-all-tags-jump) ; `C-x j t f *' +(define-key bmkp-jump-other-window-map "tf*" 'bmkp-file-all-tags-jump-other-window) ; `C-x 4 j t f *' +(define-key bmkp-jump-map "tf+" 'bmkp-file-some-tags-jump) ; `C-x j t f +' +(define-key bmkp-jump-other-window-map "tf+" 'bmkp-file-some-tags-jump-other-window) ; `C-x 4 j t f +' + +(define-key bmkp-jump-map "tf%" nil) ; For Emacs 20 +(define-key bmkp-jump-other-window-map "tf%" nil) ; For Emacs 20 +(define-key bmkp-jump-map "tf%*" 'bmkp-file-all-tags-regexp-jump) ; `C-x j t f % *' +(define-key bmkp-jump-other-window-map "tf%*" + 'bmkp-file-all-tags-regexp-jump-other-window) ; `C-x 4 j t f % *' +(define-key bmkp-jump-map "tf%+" 'bmkp-file-some-tags-regexp-jump) ; `C-x j t f % +' +(define-key bmkp-jump-other-window-map "tf%+" + 'bmkp-file-some-tags-regexp-jump-other-window) ; `C-x 4 j t f % +' + +(when (> emacs-major-version 21) ; Needs `read-file-name' with a PREDICATE arg. + (define-key bmkp-jump-map "t\C-f*" 'bmkp-find-file-all-tags) ; `C-x j t C-f *' + (define-key bmkp-jump-other-window-map "t\C-f*" + 'bmkp-find-file-all-tags-other-window) ; `C-x 4 j t C-f *' + (define-key bmkp-jump-map "t\C-f+" 'bmkp-find-file-some-tags) ; `C-x j t C-f +' + (define-key bmkp-jump-other-window-map "t\C-f+" + 'bmkp-find-file-some-tags-other-window) ; `C-x 4 j t C-f +' + (define-key bmkp-jump-map "t\C-f%*" 'bmkp-find-file-all-tags-regexp) ; `C-x j t C-f % *' + (define-key bmkp-jump-other-window-map "t\C-f%*" + 'bmkp-find-file-all-tags-regexp-other-window) ; `C-x 4 j t C-f % *' + (define-key bmkp-jump-map "t\C-f%+" + 'bmkp-find-file-some-tags-regexp) ; `C-x j t C-f % +' + (define-key bmkp-jump-other-window-map "t\C-f%+" + 'bmkp-find-file-some-tags-regexp-other-window)) ; `C-x 4 j t C-f % +' + +(define-key bmkp-jump-map "u" 'bmkp-url-jump) ; `C-x j u' +(define-key bmkp-jump-other-window-map "u" 'bmkp-url-jump-other-window) ; `C-x 4 j u' +(define-key bmkp-jump-map "v" 'bmkp-variable-list-jump) ; `C-x j v' +(define-key bmkp-jump-map "w" 'bmkp-w3m-jump) ; `C-x j w' +(define-key bmkp-jump-other-window-map "w" 'bmkp-w3m-jump-other-window) ; `C-x 4 j w' +(define-key bmkp-jump-map "\M-w" 'bmkp-snippet-to-kill-ring) ; `C-x j M-w' +(define-key bmkp-jump-other-window-map "\M-w" 'bmkp-snippet-to-kill-ring) ; SAME CMD: `C-x 4 j M-w' +(define-key bmkp-jump-map "x" 'bmkp-temporary-jump) ; `C-x j x' +(define-key bmkp-jump-other-window-map "x" 'bmkp-temporary-jump-other-window) ; `C-x 4 j x' +(define-key bmkp-jump-map "y" 'bmkp-bookmark-file-jump) ; `C-x j y' +(define-key bmkp-jump-map ":" 'bmkp-jump-to-type) ; `C-x j :' +(define-key bmkp-jump-other-window-map ":" 'bmkp-jump-to-type-other-window) ; `C-x 4 j :' + +(defun bmkp-exists-bookmark-satisfying-p (predicate &optional alist) + "Return t if there is a bookmark in ALIST that satisfies PREDICATE. +Else return nil. ALIST defaults to `bookmark-alist'. +Put differently, return t iff the filtered alist is non-empty." + (catch 'bmkp-exists-bookmark-satisfying-p + (dolist (bmk (or alist bookmark-alist)) + (when (funcall predicate bmk) (throw 'bmkp-exists-bookmark-satisfying-p t))) + nil)) + +(defun bmkp-exists-this-file/buffer-bookmarks-p (&optional alist) + "Return t if there is a this-file or this-buffer bookmark in ALIST." + (bmkp-exists-bookmark-satisfying-p (if (buffer-file-name) #'bmkp-this-file-p #'bmkp-this-buffer-p))) + +(defvar bmkp-bookmarks-here-menu-command-entries + (list (list 'bmkp-next-bookmark-this-file/buffer-repeat + 'menu-item + "Next Bookmark Here" + 'bmkp-next-bookmark-this-file/buffer-repeat + :help "Jump to the next bookmark in this buffer") + (list 'bmkp-previous-bookmark-this-file/buffer-repeat + 'menu-item + "Previous Bookmark Here" + 'bmkp-previous-bookmark-this-file/buffer-repeat + :help "Jump to the previous bookmark in this buffer") + (list 'bmkp-here-sep1 'menu-item "--") + (list 'bmkp-annotate-bookmark-this-file/buffer + 'menu-item + "Annotate a Bookmark Here" + 'bmkp-annotate-bookmark-this-file/buffer + :help "Annotate a bookmark in this buffer") + (list 'bmkp-annotate-all-bookmarks-this-file/buffer + 'menu-item + "Annotate All Bookmarks Here" + 'bmkp-annotate-all-bookmarks-this-file/buffer + :help "Annotate each bookmark in this buffer") + (list 'bmkp-edit-bookmark-record-file/buffer + 'menu-item + "Edit a Bookmark Record Here" + 'bmkp-edit-bookmark-record-file/buffer + :help "Edit the full record (Lisp) of a bookmark in this buffer") + (list 'bmkp-here-sep2 'menu-item "--") + (list 'bmkp-describe-bookmark-lighted-here + 'menu-item + "Describe Highlighted Bookmark This Line (`C-u': internal form)" + 'bmkp-describe-bookmark-lighted-here + :help "Describe a highlighted bookmark on this line. `C-u': internal description" + :enable '(and (fboundp 'bmkp-describe-bookmark-lighted-here) + (or (bmkp-a-bookmark-lighted-at-pos (point) 'FULL) + (bmkp-a-bookmark-lighted-on-this-line 'FULL)))) + (list 'bmkp-bookmarks-lighted-at-point + 'menu-item + "List Highlighted Bookmarks at Point" + 'bmkp-bookmarks-lighted-at-point + :help "List the bookmarks at point that are highlighted" + :enable '(bmkp-bookmarks-lighted-at-point)) + (list 'bmkp-set-lighting-for-this-buffer + 'menu-item + "Set Highlighting for All Bookmarks Here" + 'bmkp-set-lighting-for-this-buffer + :help "Set the `lighting' entry for all of the bookmarks for this buffer" + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-light-this-buffer + 'menu-item + "Highlight All Bookmarks Here" + 'bmkp-light-this-buffer + :help "Highlight the bookmarks in this buffer" + :keys "(C-x x H)" ; Really bound to `bmkp-light-bookmarks' + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-unlight-this-buffer + 'menu-item + "Unhighlight All Bookmarks Here" + 'bmkp-unlight-this-buffer + :help "Highlight the bookmarks in this buffer" + :keys "(C-x x U)" ; Really bound to `bmkp-unlight-bookmarks' + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-light-autonamed-this-buffer + 'menu-item + "Highlight Autonamed Bookmarks Here" + 'bmkp-light-autonamed-this-buffer + :help "Highlight the autonamed bookmarks in this buffer" + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-unlight-autonamed-this-buffer + 'menu-item + "Unhighlight Autonamed Bookmarks Here" + 'bmkp-unlight-autonamed-this-buffer + :help "Unhighlight the autonamed bookmarks in this buffer" + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-light-non-autonamed-this-buffer + 'menu-item + "Highlight Non-Autonamed Bookmarks Here" + 'bmkp-light-non-autonamed-this-buffer + :help "Highlight the non-autonamed bookmarks in this buffer" + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-unlight-non-autonamed-this-buffer + 'menu-item + "Unhighlight Non-Autonamed Bookmarks Here" + 'bmkp-unlight-non-autonamed-this-buffer + :help "Unhighlight the non-autonamed bookmarks in this buffer" + :visible (featurep 'bookmark+-lit)) + (list 'bmkp-here-sep3 'menu-item "--") + (list 'bmkp-this-file/buffer-bmenu-list + 'menu-item + "Show Bookmark List for Bookmarks Here" + 'bmkp-this-file/buffer-bmenu-list + :help "Show the bookmark list for bookmarks in this buffer") + (list 'bmkp-switch-to-bookmark-file-this-file/buffer + 'menu-item + "Switch to Bookmark File for Bookmarks Here..." + 'bmkp-switch-to-bookmark-file-this-file/buffer + :help "Switch to a bookmark file for bookmarks in this buffer") + (list 'bmkp-save-bookmarks-this-file/buffer + 'menu-item + "Save Bookmarks Here To Bookmark File..." + 'bmkp-save-bookmarks-this-file/buffer + :help "Save all bookmarks defined for this file/buffer to a file")) + "Menu entries for general commands in `Bookmarks' > `Here' menu.") + +(progn + (defvar bmkp-here-menu (make-sparse-keymap) + "`Here' submenu for menu-bar `Bookmarks' menu. +Menu for bookmarks that target this file or buffer.") + (define-prefix-command 'bmkp-here-menu) + (setcdr bmkp-here-menu bmkp-bookmarks-here-menu-command-entries)) + +;; Add commands to other keymaps: Buffer-menu, Dired, EWW, Gnus, Info, Man, Woman, W3M. + +(add-hook (if (boundp 'Buffer-menu-mode-hook) 'Buffer-menu-mode-hook 'buffer-menu-mode-hook) + (lambda () + (unless (lookup-key Buffer-menu-mode-map "j") + (define-key Buffer-menu-mode-map "j" 'bmkp-non-file-jump)) ; `j' + (define-key Buffer-menu-mode-map [menu-bar Buffer-menu-mode here] + `(menu-item "Bookmarks Here" bmkp-here-menu + :enable (and bmkp-add-bookmarks-here-menu-flag + (bmkp-exists-this-file/buffer-bookmarks-p)))))) + +(add-hook 'dired-mode-hook + (lambda () + (let ((now (lookup-key dired-mode-map "J"))) + ;; Uppercase, since `j' is `dired-goto-file'. + (unless (and now (not (eq now 'undefined))) ; `dired+.el' uses `undefined'. + (define-key dired-mode-map "J" 'bmkp-dired-jump)) ; `j' + (setq now (lookup-key dired-mode-map "\C-j")) + (unless (and now (not (eq now 'undefined))) ; `dired+.el' uses `undefined'. + (define-key dired-mode-map "\C-j" 'bmkp-dired-this-dir-jump))) ; `C-j' + (let ((map dired-mode-map) + (sep '(menu-bar subdir separator-bmkp)) + (bdj '(menu-bar subdir bmkp-dired-jump)) + (bdjc '(menu-bar subdir bmkp-dired-this-dir-jump))) + (cond ((boundp 'diredp-bookmark-menu) ; In `dired+el'. + (setq map diredp-bookmark-menu + sep (cddr sep) + bdj (cddr bdj) + bdjc (cddr bdjc)) + (define-key map (apply #'vector bdjc) + '(menu-item "Jump to a Dired Bookmark For This Dir" bmkp-dired-this-dir-jump + :help "Jump to a bookmarked Dired buffer for this directory")) + (define-key map (apply #'vector bdj) + '(menu-item "Jump to a Dired Bookmark" bmkp-dired-jump + :help "Jump to a bookmarked Dired buffer")) + (define-key map [bookmarks-here] + `(menu-item "Here" bmkp-here-menu + :enable (and bmkp-add-bookmarks-here-menu-flag + (bmkp-exists-this-file/buffer-bookmarks-p))))) + (t + (define-key map (apply #'vector sep) '("--")) ;------------------------ + (define-key map (apply #'vector bdjc) + '(menu-item "Jump to a Dired Bookmark For This Dir" bmkp-dired-this-dir-jump + :help "Jump to a bookmarked Dired buffer for this directory")) + (define-key map (apply #'vector bdj) + '(menu-item "Jump to a Dired Bookmark" bmkp-dired-jump + :help "Jump to a bookmarked Dired buffer")) + (define-key map [bookmarks-here] + `(menu-item "Here" bmkp-here-menu + :enable (and bmkp-add-bookmarks-here-menu-flag + (bmkp-exists-this-file/buffer-bookmarks-p))))))))) + +(when (fboundp 'bmkp-eww-jump) ; Emacs 24.4+ + (add-hook 'eww-mode-hook + (lambda () (unless (lookup-key eww-mode-map "j") + (define-key eww-mode-map "j" 'bmkp-eww-jump))))) + +(add-hook 'gnus-summary-mode-hook + (lambda () (unless (lookup-key gnus-summary-mode-map "j") + (define-key gnus-summary-mode-map "j" 'bmkp-gnus-jump)))) + +(add-hook 'Info-mode-hook + (lambda () + (unless (lookup-key Info-mode-map "j") + (define-key Info-mode-map "j" 'bmkp-info-jump)) + (define-key-after Info-mode-menu [bmkp-info-jump] + '(menu-item "Jump to an Info Bookmark" bmkp-info-jump + :help "Jump to a bookmarked Info node") + 'Go\ to\ Node\.\.\.) ; Used by `info(+).el' - corresponds to `Info-goto-node'. + (define-key Info-mode-menu [bookmarks-here] + `(menu-item "Bookmarks Here" bmkp-here-menu + :enable (and bmkp-add-bookmarks-here-menu-flag + (bmkp-exists-this-file/buffer-bookmarks-p)))))) + +(add-hook 'Man-mode-hook + (lambda () (unless (lookup-key Man-mode-map "j") + (define-key Man-mode-map "j" 'bmkp-man-jump)))) + +(add-hook 'woman-mode-hook + (lambda () + (unless (lookup-key woman-mode-map "j") (define-key woman-mode-map "j" 'bmkp-man-jump)) + (when (boundp 'woman-menu) + (define-key-after woman-menu [bmkp-man-jump] + '(menu-item "Jump to a `man'-page Bookmark" bmkp-man-jump + :help "Jump to a bookmarked `man' page") + 'WoMan\.\.\.)))) ; Used by `woman.el' - corresponds to command `woman'. + +(add-hook 'w3m-minor-mode-hook + (lambda () (unless (lookup-key w3m-minor-mode-map "j") + (define-key w3m-minor-mode-map "j" 'bmkp-w3m-jump)))) + +(add-hook 'w3m-mode-hook + (lambda () (unless (lookup-key w3m-mode-map "j") + (define-key w3m-mode-map "j" 'bmkp-w3m-jump)))) + + +;;; Vanilla Emacs `Bookmarks' menu (see also [jump] from `Bookmark+' menu, below). + +(define-key-after menu-bar-bookmark-map [separator-edit] '("--") ;------------------------------------- + 'jump) +;; Remove this predefined item - we use `bmkp-edit-bookmark-name-and-location' instead. +(define-key menu-bar-bookmark-map [rename] nil) + +(define-key-after menu-bar-bookmark-map [bmkp-clone-bookmark] + '(menu-item "Clone (Duplicate) a Bookmark" bmkp-clone-bookmark + :help "Clone this bookmark. (`\\[bmkp-edit-bookmark-record]' to edit.)") + 'separator-edit) +(define-key-after menu-bar-bookmark-map [bmkp-edit-bookmark-name-and-location] + '(menu-item "Rename or Relocate Bookmark..." bmkp-edit-bookmark-name-and-location + :help "Rename and/or relocate a bookmark") + 'bmkp-clone-bookmark) +(define-key-after menu-bar-bookmark-map [bmkp-edit-bookmark-record] + '(menu-item "Edit Bookmark Record (Lisp)..." bmkp-edit-bookmark-record + :help "Edit the internal record of a bookmark,a Lisp sexp") + 'bmkp-edit-bookmark-name-and-location) + +(define-key-after menu-bar-bookmark-map [separator-show] '("--") ;------------------------------------- + 'bmkp-edit-bookmark-record) +(define-key-after menu-bar-bookmark-map [edit] + '(menu-item "Show Bookmark List" bookmark-bmenu-list + :help "Open the list of bookmarks in buffer `*Bookmark List*'") + 'separator-show) +(define-key-after menu-bar-bookmark-map [bmkp-this-file/buffer-bmenu-list] + '(menu-item "Show Bookmark List for This File/Buffer" bmkp-this-file/buffer-bmenu-list + :help "Open `*Bookmark List*' for the bookmarks in the current buffer (only)") + 'edit) +(define-key-after menu-bar-bookmark-map [bmkp-navlist-bmenu-list] + '(menu-item "Show Bookmark List for Navlist" bmkp-navlist-bmenu-list + :help "Open `*Bookmark List*' for bookmarks in navlist (only)") + 'bmkp-this-file/buffer-bmenu-list) + +(define-key-after menu-bar-bookmark-map [separator-2] '("--") ;------------------------------------- + 'bmkp-navlist-bmenu-list) +(define-key-after menu-bar-bookmark-map [bmkp-choose-navlist-of-type] + '(menu-item "Set Navlist to Bookmarks of Type..." bmkp-choose-navlist-of-type + :help "Set the navigation list to the bookmarks of a certain type") + 'separator-2) +(define-key-after menu-bar-bookmark-map [bmkp-choose-navlist-from-bookmark-list] + '(menu-item "Set Navlist from Bookmark-List Bookmark..." bmkp-choose-navlist-from-bookmark-list + :help "Set the navigation list from a bookmark-list bookmark") + 'bmkp-choose-navlist-of-type) +(define-key-after menu-bar-bookmark-map [bmkp-list-defuns-in-commands-file] + '(menu-item "List User-Defined Bookmark Commands" bmkp-list-defuns-in-commands-file + :help "List the functions defined in `bmkp-bmenu-commands-file'" + :enable (and bmkp-bmenu-commands-file (file-readable-p bmkp-bmenu-commands-file))) + 'bmkp-choose-navlist-from-bookmark-list) + +(define-key-after menu-bar-bookmark-map [insert] + '(menu-item "Insert Bookmark Contents..." bookmark-insert :help "Insert bookmarked text") + 'bmkp-choose-navlist-from-bookmark-list) +(define-key-after menu-bar-bookmark-map [locate] + '(menu-item "Insert Bookmark Location..." bookmark-locate ; Alias for `bookmark-insert-location'. + :help "Insert a bookmark's file or buffer name") + 'insert) +(when (fboundp 'advice-add) ; Emacs 24.4+. + (define-key-after menu-bar-bookmark-map [bmkp-store-org-link] + '(menu-item "Store Org Link To..." bmkp-store-org-link + :help "Store a link to a bookmark for insertion in an Org-mode buffer") + 'locate)) + +(define-key-after menu-bar-bookmark-map [separator-3] '("--") ;------------------------------------- + (if (fboundp 'advice-add) 'bmkp-store-org-link 'locate)) +(define-key-after menu-bar-bookmark-map [save] + '(menu-item "Save Bookmarks" bookmark-save :help "Save currently defined bookmarks") + 'separator-3) +(define-key-after menu-bar-bookmark-map [write] + '(menu-item "Save Bookmarks As..." bookmark-write + :help "Write current bookmarks to a bookmark file") + 'save) +(define-key-after menu-bar-bookmark-map [bmkp-switch-bookmark-file-create] + '(menu-item "Switch to Bookmark File..." bmkp-switch-bookmark-file-create + :help "Switch to a different bookmark file, *replacing* the current set of bookmarks") + 'write) +(define-key-after menu-bar-bookmark-map [load] + '(menu-item "Add Bookmarks from File..." bookmark-load + :help "Load additional bookmarks from a bookmark file") + 'bmkp-switch-bookmark-file-create) +(define-key-after menu-bar-bookmark-map [bmkp-empty-file] + '(menu-item "Empty Bookmark File..." bmkp-empty-file + :help "Empty an existing bookmark file or create a new, empty bookmark file") + 'load) + + +;; `bmkp-annotate-menu' of vanilla `Bookmarks' menu: `Annotate' + +(defvar bmkp-annotate-menu (make-sparse-keymap) + "`Annotate' submenu for menu-bar `Bookmarks' menu.") +(define-key menu-bar-bookmark-map [annotate] (cons "Annotate" bmkp-annotate-menu)) + +(define-key bmkp-annotate-menu [bookmark-show-all-annotations] + '(menu-item "Show All Annotations" bookmark-show-all-annotations + :help "Show the annotations for all bookmarks")) +(define-key bmkp-annotate-menu [bookmark-show-annotation] + '(menu-item "Show an Annotation" bookmark-show-annotation + :help "Show the annotation for a bookmark, or follow it if external")) +(define-key bmkp-annotate-menu [bmkp-annotate-all-bookmarks-this-file/buffer] + '(menu-item "Annotate All Bookmarks Here" bmkp-annotate-all-bookmarks-this-file/buffer + :help "Pop up an annotation-editing buffer for each bookmark in this buffer")) +(define-key bmkp-annotate-menu [bmkp-annotate-bookmark-this-file/buffer] + '(menu-item "Annotate a Bookmark Here" bmkp-annotate-bookmark-this-file/buffer + :help "Annotate an existing bookmark in this buffer")) +(define-key bmkp-annotate-menu [bmkp-annotate-bookmark] + '(menu-item "Annotate a Bookmark" bmkp-annotate-bookmark + :help "Pop up a buffer to add or edit an annotation for a bookmark")) + + +;; `bmkp-highlight-menu' of vanilla `Bookmarks' menu: `Highlight' + +(when (or (featurep 'bookmark+-lit) + (and (fboundp 'diredp-highlight-autofiles-mode) (featurep 'highlight))) + (defvar bmkp-highlight-menu (make-sparse-keymap) + "`Highlight' submenu for menu-bar `Bookmarks' menu.") + (define-key menu-bar-bookmark-map [highlight] (cons "Highlight" bmkp-highlight-menu)) + + (when (featurep 'bookmark+-lit) + (define-key bmkp-highlight-menu [bmkp-unlight-bookmarks] + '(menu-item "Unhighlight All" bmkp-unlight-bookmarks + :help "Unhighlight all bookmarks (everywhere)")) + (define-key bmkp-highlight-menu [bmkp-unlight-this-buffer] + '(menu-item "Unhighlight All in Buffer" bmkp-unlight-this-buffer + :help "Unhighlight all bookmarks in this buffer")) + (define-key bmkp-highlight-menu [bmkp-unlight-non-autonamed-this-buffer] + '(menu-item "Unhighlight All Non-Autonamed in Buffer" bmkp-unlight-non-autonamed-this-buffer + :help "Unhighlight all non-autonamed bookmarks in this buffer")) + (define-key bmkp-highlight-menu [bmkp-unlight-autonamed-this-buffer] + '(menu-item "Unhighlight All Autonamed in Buffer" bmkp-unlight-autonamed-this-buffer + :help "Unhighlight all autonamed bookmarks in this buffer")) + (define-key bmkp-highlight-menu [bmkp-unlight-bookmark] + '(menu-item "Unhighlight One..." bmkp-unlight-bookmark + :help "Unhighlight a bookmark")) + (define-key bmkp-highlight-menu [bmkp-unlight-bookmark-this-buffer] + '(menu-item "Unhighlight One in Buffer..." bmkp-unlight-bookmark-this-buffer + :help "Unhighlight a bookmark in this buffer")) + (define-key bmkp-highlight-menu [bmkp-unlight-bookmark-here] + '(menu-item "Unhighlight This One" bmkp-unlight-bookmark-here + :help "Unhighlight a bookmark at point or on its line")) + + (define-key bmkp-highlight-menu [separator-2] '("--")) ;------------------------------------------ + (define-key bmkp-highlight-menu [bmkp-light-bookmarks-in-region] + '(menu-item "Highlight All in Region" bmkp-light-bookmarks-in-region + :help "Highlight all bookmarks in the region")) + (define-key bmkp-highlight-menu [bmkp-light-this-buffer] + '(menu-item "Highlight All in Buffer" bmkp-light-this-buffer + :help "Highlight all bookmarks in this buffer")) + (define-key bmkp-highlight-menu [bmkp-light-non-autonamed-this-buffer] + '(menu-item "Highlight All Non-Autonamed in Buffer" bmkp-light-non-autonamed-this-buffer + :help "Highlight all non-autonamed bookmarks in this buffer")) + (define-key bmkp-highlight-menu [bmkp-light-autonamed-this-buffer] + '(menu-item "Highlight All Autonamed in Buffer" bmkp-light-autonamed-this-buffer + :help "Highlight all autonamed bookmarks in this buffer")) + (define-key bmkp-highlight-menu [bmkp-light-navlist-bookmarks] + '(menu-item "Highlight All in Navigation List" bmkp-light-navlist-bookmarks + :help "Highlight all bookmarks in the navigation list")) + (define-key bmkp-highlight-menu [bmkp-light-bookmark-this-buffer] + '(menu-item "Highlight One in Buffer..." bmkp-light-bookmark-this-buffer + :help "Highlight a bookmark in this buffer")) + (define-key bmkp-highlight-menu [bmkp-light-bookmark] + '(menu-item "Highlight One..." bmkp-light-bookmark + :help "Highlight a bookmark")) + + (define-key bmkp-highlight-menu [separator-1] '("--")) ;------------------------------------------ + (define-key bmkp-highlight-menu [bmkp-describe-bookmark-lighted-here] + '(menu-item "Describe Highlighted Here (`C-u': internal form)" + bmkp-describe-bookmark-lighted-here + :help "Describe a highlighted bookmark on this line." + :enable (and (fboundp 'bmkp-describe-bookmark-lighted-here) + (or (bmkp-a-bookmark-lighted-at-pos (point) 'FULL) + (bmkp-a-bookmark-lighted-on-this-line 'FULL))))) + (define-key bmkp-highlight-menu [bmkp-bookmarks-lighted-at-point] + '(menu-item "List Highlighted at Point" bmkp-bookmarks-lighted-at-point + :help "List the bookmarks at point that are highlighted" + :enable (bmkp-bookmarks-lighted-at-point))) + (define-key bmkp-highlight-menu [bmkp-next-lighted-this-buffer] + '(menu-item "Next in Buffer" bmkp-next-lighted-this-buffer + :help "Cycle to the next highlighted bookmark in this buffer")) + (define-key bmkp-highlight-menu [bmkp-previous-lighted-this-buffer] + '(menu-item "Previous in Buffer" bmkp-previous-lighted-this-buffer + :help "Cycle to the previous highlighted bookmark in this buffer")) + (define-key bmkp-highlight-menu [separator-0] '("--")) ;------------------------------------------ + ) + + (define-key bmkp-highlight-menu [diredp-highlight-autofiles-mode] + (bmkp-menu-bar-make-toggle diredp-highlight-autofiles-mode + diredp-highlight-autofiles-mode + "Toggle Autofile Highlighting in Dired" + "Whether to highlight autofile bookmarks in Dired us biw %s" + "Toggle `diredp-highlight-autofiles-mode'" + nil + :visible (and (fboundp 'diredp-highlight-autofiles-mode) + (featurep 'highlight)))) + + (when (featurep 'bookmark+-lit) + (define-key bmkp-highlight-menu [bmkp-set-lighting-for-bookmark] + '(menu-item "Set Highlighting for One..." bmkp-set-lighting-for-bookmark + :help "Set individual highlighting for a bookmark")))) + + +;; `bmkp-here-menu' of vanilla `Bookmarks' menu: `Here' + +(define-key menu-bar-bookmark-map [bookmarks-here] + `(menu-item "Here (This File/Buffer)" bmkp-here-menu + :enable (and bmkp-add-bookmarks-here-menu-flag + (bmkp-exists-this-file/buffer-bookmarks-p)))) + + +;; `bmkp-delete-menu' of vanilla `Bookmarks' menu: `Delete' + +(defvar bmkp-delete-menu (make-sparse-keymap) + "`Delete' submenu for menu-bar `Bookmarks' menu.") +(define-key menu-bar-bookmark-map [delete-menu] (cons "Delete" bmkp-delete-menu)) + +(define-key bmkp-delete-menu [bmkp-delete-all-temporary-bookmarks] + '(menu-item "Delete All Temporaries..." bmkp-delete-all-temporary-bookmarks + :help "Delete the temporary bookmarks, (`X') whether visible here or not")) + +;;; $$$$$$ NOTE: Here and below, the definitions with logically correct `:enable' filters are +;;; commented out. This is because evaluation of these filters is too slow, especially +;;; in older Emacs versions. If you want to try some or all of the definitions with the +;;; `:enable' conditions, just uncomment them and comment out or remove the corresponding +;;; definitions without such conditions. + +;;;;; (define-key bmkp-delete-menu [bmkp-delete-all-autonamed-for-this-buffer] +;;;;; '(menu-item "Delete All Autonamed Bookmarks Here..." +;;;;; bmkp-delete-all-autonamed-for-this-buffer +;;;;; :help "Delete all autonamed bookmarks for the current buffer" +;;;;; :enable (mapcar #'bmkp-bookmark-name-from-record (bmkp-autonamed-this-buffer-alist-only)))) +(define-key bmkp-delete-menu [bmkp-delete-all-autonamed-for-this-buffer] + '(menu-item "Delete All Autonamed Bookmarks Here..." + bmkp-delete-all-autonamed-for-this-buffer + :help "Delete all autonamed bookmarks for the current buffer")) +(define-key bmkp-delete-menu [bmkp-toggle-autoname-bookmark-delete] + '(menu-item "Delete Autonamed Bookmark" bmkp-toggle-autonamed-bookmark-set/delete + :help "Delete the autonamed bookmark at point" + :visible (bmkp-get-bookmark-in-alist (funcall bmkp-autoname-bookmark-function (point)) + 'noerror))) +;;;;; (define-key bmkp-delete-menu [bmkp-delete-bookmarks] +;;;;; '(menu-item "Delete Bookmarks Here..." bmkp-delete-bookmarks +;;;;; :help "Delete some bookmarks at point or, with `C-u', all bookmarks in the buffer" +;;;;; :enable (mapcar #'bmkp-bookmark-name-from-record (bmkp-this-buffer-alist-only)))) +(define-key bmkp-delete-menu [bmkp-delete-bookmarks] + '(menu-item "Delete Bookmarks Here..." bmkp-delete-bookmarks + :help "Delete some bookmarks at point or, with `C-u', all bookmarks in the buffer")) +(define-key bmkp-delete-menu [delete] + '(menu-item "Delete Bookmark..." bookmark-delete :help "Delete the bookmark you choose by name")) +(define-key bmkp-delete-menu [bmkp-purge-notags-autofiles] + '(menu-item "Purge Autofiles with No Tags..." bmkp-purge-notags-autofiles + :help "Delete all autofile bookmarks that have no tags")) + +;; Remove vanilla `bookmark-delete' entry from main `Bookmarks' menu. +(define-key menu-bar-bookmark-map [delete] nil) + + +;; `bmkp-set-bookmark-menu' of vanilla `Bookmarks' menu: `New/Update' +(defvar bmkp-set-bookmark-menu (make-sparse-keymap) + "`New/Update' submenu for menu-bar `Bookmarks' menu.") +(define-key menu-bar-bookmark-map [set-bookmark] (cons "New/Update" bmkp-set-bookmark-menu)) + +(defun bmkp-menu-bar-set-bookmark () + "Set a bookmark, prompting for the name." + (interactive) + (call-interactively #'bmkp-bookmark-set-confirm-overwrite)) + +(define-key bmkp-set-bookmark-menu [bmkp-make-function-bookmark] + '(menu-item "Function Bookmark..." bmkp-make-function-bookmark + :help "Create a bookmark that will invoke a function when \"jumped\" to")) +(define-key bmkp-set-bookmark-menu [bmkp-toggle-autoname-bookmark-set] + '(menu-item "Autonamed Bookmark" bmkp-toggle-autonamed-bookmark-set/delete + :help "Set an autonamed bookmark at point" + :visible (not (bmkp-get-bookmark-in-alist (funcall bmkp-autoname-bookmark-function (point)) + 'NOERROR)))) +(define-key bmkp-set-bookmark-menu [bmkp-set-bookmark-file-bookmark] + '(menu-item "Bookmark-File Bookmark..." bmkp-set-bookmark-file-bookmark + :help "Set a bookmark that loads a bookmark file when jumped to")) +(define-key bmkp-set-bookmark-menu [bmkp-set-desktop-bookmark] + '(menu-item "Desktop Bookmark" bmkp-set-desktop-bookmark + :help "Save the current desktop as a bookmark")) +(define-key bmkp-set-bookmark-menu [bmkp-url-target-set] + '(menu-item "URL Bookmark..." bmkp-url-target-set + :help "Set a bookmark for a given URL")) +(define-key bmkp-set-bookmark-menu [bmkp-file-target-set] + '(menu-item "File Bookmark..." bmkp-file-target-set + :help "Set a bookmark with a given name for a given file")) +(define-key bmkp-set-bookmark-menu [bmkp-autofile-set] + '(menu-item "Autofile Bookmark..." bmkp-autofile-set + :help "Set and automatically name a bookmark for a given file")) +(define-key bmkp-set-bookmark-menu [bmkp-menu-bar-set-bookmark] + '(menu-item "Ordinary Bookmark..." bmkp-menu-bar-set-bookmark + :help "Set a bookmark at point" :keys "(C-x x m)")) ; Really bound to `bookmark-set' + + +;; Remove vanilla `bookmark-set' from main `Bookmarks' menu. +(define-key menu-bar-bookmark-map [set] nil) + + +;; `bmkp-options-menu' of vanilla `Bookmarks' menu: `Toggle'. Reuse `bmkp-bmenu-toggle-menu'. +(define-key menu-bar-bookmark-map [options] (cons "Toggle" bmkp-bmenu-toggle-menu)) + + +;; `bmkp-tags-menu' of vanilla `Bookmarks' menu: `Tags' + +(defvar bmkp-tags-menu (make-sparse-keymap) + "`Tags' submenu for menu-bar `Bookmarks' menu.") +(define-key menu-bar-bookmark-map [tags] (cons "Tags" bmkp-tags-menu)) + +(define-key bmkp-tags-menu [bmkp-list-all-tags] + '(menu-item "List All Tags" bmkp-list-all-tags :help "List all tags used for any bookmarks")) +(define-key bmkp-tags-menu [bmkp-purge-notags-autofiles] + '(menu-item "Purge Autofiles with No Tags..." bmkp-purge-notags-autofiles + :help "Delete all autofile bookmarks that have no tags")) +(define-key bmkp-tags-menu [bmkp-untag-a-file] + '(menu-item "Untag a File (Remove Some)..." bmkp-untag-a-file + :help "Remove some tags from autofile bookmark for a file")) +(define-key bmkp-tags-menu [bmkp-tag-a-file] + '(menu-item "Tag a File (Add Some)..." bmkp-tag-a-file + :help "Add some tags to the autofile bookmark for a file")) + +(define-key bmkp-tags-menu [tags-sep1] '("--")) ;---------------------------------------------- +(define-key bmkp-tags-menu [bmkp-rename-tag] + '(menu-item "Rename Tag..." bmkp-rename-tag :help "Rename a tag in all bookmarks")) +(define-key bmkp-tags-menu [bmkp-set-tag-value] + '(menu-item "Set Tag Value..." bmkp-set-tag-value :help "Set the tag value for a given bookmark")) +(define-key bmkp-tags-menu [bmkp-remove-tags-from-all] + '(menu-item "Remove Some Tags from All..." bmkp-remove-tags-from-all + :help "Remove a set of tags from all bookmarks")) +(define-key bmkp-tags-menu [bmkp-remove-tags] + '(menu-item "Remove Some Tags..." bmkp-remove-tags :help "Remove a set of tags from a bookmark")) +(define-key bmkp-tags-menu [bmkp-add-tags] + '(menu-item "Add Some Tags..." bmkp-add-tags :help "Add a set of tags to a bookmark")) +(define-key bmkp-tags-menu [bmkp-paste-replace-tags] + '(menu-item "Paste Tags (Replace)..." bmkp-paste-replace-tags + :help "Replace tags for a bookmark with tags copied from another")) +(define-key bmkp-tags-menu [bmkp-paste-add-tags] + '(menu-item "Paste Tags (Add)..." bmkp-paste-add-tags + :help "Add tags to a bookmark that were previously copied from another")) +(define-key bmkp-tags-menu [bmkp-copy-tags] + '(menu-item "Copy Tags..." bmkp-copy-tags + :help "Copy the tags from a bookmark, so you can paste them to another")) +(define-key bmkp-tags-menu [bmkp-edit-tags] + '(menu-item "Edit Tags..." bmkp-edit-tags :help "Edit the tags of a bookmark")) + + +;; `bmkp-jump-menu' of vanilla `Bookmarks' menu: `Jump To' + +(defvar bmkp-jump-menu (make-sparse-keymap) + "`Jump To' submenu for menu-bar `Bookmarks' menu.") +;; Add jump menu to vanilla Emacs `Bookmarks' menu and remove the two jump commands already there. +(define-key menu-bar-bookmark-map [jump] nil) +(define-key menu-bar-bookmark-map [jump-other] nil) +(define-key menu-bar-bookmark-map [bmkp-jump] (cons "Jump To" bmkp-jump-menu)) + +;; `Jump To': Add jump menu also to the `Bookmark+' menu, and remove the two jump commands there. +(define-key bmkp-bmenu-menubar-menu [jump] (cons "Jump To" bmkp-jump-menu)) + +(define-key bmkp-jump-menu [bmkp-temporary-jump-other-window] + '(menu-item "Temporary..." bmkp-temporary-jump-other-window + :help "Jump to a temporary bookmark")) +(define-key bmkp-jump-menu [bmkp-autofile-jump-other-window] + '(menu-item "Autofile..." bmkp-autofile-jump-other-window + :help "Jump to an autofile bookmark")) +(define-key bmkp-jump-menu [bmkp-autonamed-this-buffer-jump] + '(menu-item "Autonamed for This Buffer..." bmkp-autonamed-this-buffer-jump + :help "Jump to an autonamed bookmark in this buffer")) +(define-key bmkp-jump-menu [bmkp-autonamed-jump-other-window] + '(menu-item "Autonamed..." bmkp-autonamed-jump-other-window + :help "Jump to an autonamed bookmark")) +(define-key bmkp-jump-menu [bmkp-specific-files-jump-other-window] + '(menu-item "For Specific Files..." bmkp-specific-files-jump-other-window + :help "Jump to a bookmark for specific files")) +(define-key bmkp-jump-menu [bmkp-specific-buffers-jump-other-window] + '(menu-item "For Specific Buffers..." bmkp-specific-buffers-jump-other-window + :help "Jump to a bookmark for specific buffers")) +;;;;; (define-key bmkp-jump-menu [bmkp-this-buffer-jump] +;;;;; '(menu-item "For This Buffer..." bmkp-this-buffer-jump +;;;;; :help "Jump to a bookmark for the current buffer" +;;;;; :enable (mapcar #'bmkp-bookmark-name-from-record (bmkp-this-buffer-alist-only)))) +(define-key bmkp-jump-menu [bmkp-this-buffer-jump] + '(menu-item "For This Buffer..." bmkp-this-buffer-jump + :help "Jump to a bookmark for the current buffer")) +;;;;; (when (featurep 'bookmark+-lit) +;;;;; (define-key bmkp-jump-menu [bmkp-lighted-jump-other-window] +;;;;; '(menu-item "Highlighted..." bmkp-lighted-jump-other-window +;;;;; :help "Jump to a highlighted bookmark" +;;;;; :enable (bmkp-lighted-alist-only)))) +(when (featurep 'bookmark+-lit) + (define-key bmkp-jump-menu [bmkp-lighted-jump-other-window] + '(menu-item "Highlighted..." bmkp-lighted-jump-other-window + :help "Jump to a highlighted bookmark"))) +(define-key bmkp-jump-menu [bmkp-jump-in-navlist-other-window] + '(menu-item "In Navigation List..." bmkp-jump-in-navlist-other-window + :help "Jump to a bookmark that is in the navigation list" :enable bmkp-nav-alist)) + +(define-key bmkp-jump-menu [jump-sep0] '("--")) ;--------------------------------------------------- +;;;;; (define-key bmkp-jump-menu [bmkp-url-jump-other-window] +;;;;; '(menu-item "URL..." bmkp-url-jump-other-window :help "Jump to a URL bookmark" +;;;;; :enable (bmkp-url-alist-only))) +(define-key bmkp-jump-menu [bmkp-url-jump-other-window] + '(menu-item "URL..." bmkp-url-jump-other-window :help "Jump to a URL bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-gnus-jump-other-window] +;;;;; '(menu-item "Gnus..." bmkp-gnus-jump-other-window :help "Jump to a Gnus bookmark" +;;;;; :enable (bmkp-gnus-alist-only))) +(define-key bmkp-jump-menu [bmkp-gnus-jump-other-window] + '(menu-item "Gnus..." bmkp-gnus-jump-other-window :help "Jump to a Gnus bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-man-jump-other-window] +;;;;; '(menu-item "Man Page..." bmkp-man-jump-other-window :help "Jump to a `man'-page bookmark" +;;;;; :enable (bmkp-man-alist-only))) +(define-key bmkp-jump-menu [bmkp-man-jump-other-window] + '(menu-item "Man Page..." bmkp-man-jump-other-window :help "Jump to a `man'-page bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-info-jump-other-window] +;;;;; '(menu-item "Info Node..." bmkp-info-jump-other-window :help "Jump to an Info bookmark" +;;;;; :enable (bmkp-info-alist-only))) +(define-key bmkp-jump-menu [bmkp-info-jump-other-window] + '(menu-item "Info Node..." bmkp-info-jump-other-window :help "Jump to an Info bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-image-jump-other-window] +;;;;; '(menu-item "Image..." bmkp-image-jump-other-window :help "Jump to an image-file bookmark" +;;;;; :enable (bmkp-image-alist-only))) +(define-key bmkp-jump-menu [bmkp-image-jump-other-window] + '(menu-item "Image..." bmkp-image-jump-other-window :help "Jump to an image-file bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-non-file-jump-other-window] +;;;;; '(menu-item "Buffer (Non-File)..." bmkp-non-file-jump-other-window +;;;;; :help "Jump to a non-file (buffer) bookmark" :enable (bmkp-non-file-alist-only))) +(define-key bmkp-jump-menu [bmkp-non-file-jump-other-window] + '(menu-item "Buffer (Non-File)..." bmkp-non-file-jump-other-window + :help "Jump to a non-file (buffer) bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-region-jump-other-window] +;;;;; '(menu-item "Region..." bmkp-region-jump-other-window +;;;;; :help "Jump to a bookmark that defines the active region" :enable (bmkp-region-alist-only))) +(define-key bmkp-jump-menu [bmkp-region-jump-other-window] + '(menu-item "Region..." bmkp-region-jump-other-window + :help "Jump to a bookmark that defines the active region")) +;;;;; (define-key bmkp-jump-menu [bmkp-remote-file-jump-other-window] +;;;;; '(menu-item "Remote File..." bmkp-remote-file-jump-other-window +;;;;; :help "Jump to a remote file or directory bookmark" :enable (bmkp-remote-file-alist-only))) +(define-key bmkp-jump-menu [bmkp-remote-file-jump-other-window] + '(menu-item "Remote File..." bmkp-remote-file-jump-other-window + :help "Jump to a remote file or directory bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-local-file-jump-other-window] +;;;;; '(menu-item "Local File..." bmkp-local-file-jump-other-window +;;;;; :help "Jump to a local file or directory bookmark" :enable (bmkp-local-file-alist-only))) +(define-key bmkp-jump-menu [bmkp-local-file-jump-other-window] + '(menu-item "Local File..." bmkp-local-file-jump-other-window + :help "Jump to a local file or directory bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-file-this-dir-jump-other-window] +;;;;; '(menu-item "File in This Dir..." bmkp-file-this-dir-jump-other-window +;;;;; :help "Jump to a bookmark for a file or subdirectory in the `default-directory'." +;;;;; :enable (bmkp-file-alist-only))) +(define-key bmkp-jump-menu [bmkp-file-this-dir-jump-other-window] + '(menu-item "File in This Dir..." bmkp-file-this-dir-jump-other-window + :help "Jump to a bookmark for a file or subdirectory in the `default-directory'.")) +;;;;; (define-key bmkp-jump-menu [bmkp-file-jump-other-window] +;;;;; '(menu-item "File..." bmkp-file-jump-other-window :help "Jump to a file or directory bookmark" +;;;;; :enable (bmkp-file-alist-only))) +(define-key bmkp-jump-menu [bmkp-file-jump-other-window] + '(menu-item "File..." bmkp-file-jump-other-window :help "Jump to a file or directory bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-dired-this-dir-jump-other-window] +;;;;; '(menu-item "Dired for This Dir..." bmkp-dired-this-dir-jump-other-window +;;;;; :help "Jump to a Dired bookmark for `default-directory', restoring recorded state" +;;;;; :enable (bmkp-dired-alist-only))) +(define-key bmkp-jump-menu [bmkp-dired-this-dir-jump-other-window] + '(menu-item "Dired for This Dir..." bmkp-dired-this-dir-jump-other-window + :help "Jump to a Dired bookmark for `default-directory', restoring recorded state")) +;;;;; (define-key bmkp-jump-menu [bmkp-dired-jump-other-window] +;;;;; '(menu-item "Dired..." bmkp-dired-jump-other-window +;;;;; :help "Jump to a Dired bookmark, restoring the recorded Dired state" +;;;;; :enable (bmkp-dired-alist-only))) +(define-key bmkp-jump-menu [bmkp-dired-jump-other-window] + '(menu-item "Dired..." bmkp-dired-jump-other-window + :help "Jump to a Dired bookmark, restoring the recorded Dired state")) +;;;;; (define-key bmkp-jump-menu [bmkp-variable-list-jump] +;;;;; '(menu-item "Variable List..." bmkp-variable-list-jump :help "Jump to a variable-list bookmark" +;;;;; :enable (bmkp-variable-list-alist-only))) +(define-key bmkp-jump-menu [bmkp-variable-list-jump] + '(menu-item "Variable List..." bmkp-variable-list-jump :help "Jump to a variable-list bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-bookmark-file-jump] +;;;;; '(menu-item "Bookmark File..." bmkp-bookmark-file-jump +;;;;; :help "Jump to (load) a bookmark-file bookmark" :enable (bmkp-bookmark-file-alist-only))) +(define-key bmkp-jump-menu [bmkp-bookmark-file-jump] + '(menu-item "Bookmark File..." bmkp-bookmark-file-jump + :help "Jump to (load) a bookmark-file bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-bookmark-list-jump] +;;;;; '(menu-item "Bookmark List..." bmkp-bookmark-list-jump :help "Jump to a bookmark-list bookmark" +;;;;; :enable (bmkp-bookmark-list-alist-only))) +(define-key bmkp-jump-menu [bmkp-bookmark-list-jump] + '(menu-item "Bookmark List..." bmkp-bookmark-list-jump :help "Jump to a bookmark-list bookmark")) +;;;;; (define-key bmkp-jump-menu [bmkp-desktop-jump] +;;;;; '(menu-item "Desktop..." bmkp-desktop-jump :help "Jump to a desktop bookmark" +;;;;; :enable (bmkp-desktop-alist-only))) +(define-key bmkp-jump-menu [bmkp-desktop-jump] + '(menu-item "Desktop..." bmkp-desktop-jump :help "Jump to a desktop bookmark")) +(define-key bmkp-jump-menu [bmkp-jump-to-type-other-window] + '(menu-item "Of Type..." bmkp-jump-to-type-other-window + :help "Jump to a bookmark of a type that you specify")) + +(define-key bmkp-jump-menu [bookmark-jump-other-window] + '(menu-item "Any in Other Window..." bookmark-jump-other-window + :help "Jump to a bookmark of any type, in another window")) +(define-key bmkp-jump-menu [bookmark-jump] + '(menu-item "Any..." bookmark-jump :help "Jump to a bookmark of any type, in this window")) + +(define-key bmkp-jump-menu [bmkp-bmenu-jump-to-marked] + '(menu-item "Marked" bmkp-bmenu-jump-to-marked + :help "Jump to each bookmark marked `>', in another window" + :enable (and bmkp-bmenu-marked-bookmarks (equal (buffer-name (current-buffer)) + bmkp-bmenu-buffer)))) + + +;; `bmkp-jump-tags-menu' of vanilla `Bookmarks' menu: `Jump To' > `With Tags' + +(defvar bmkp-jump-tags-menu (make-sparse-keymap) + "`With Tags' submenu for `Jump To' submenu of `Bookmarks' menu.") +(define-key bmkp-jump-menu [bmkp-tags] (cons "With Tags" bmkp-jump-tags-menu)) +(define-key bmkp-jump-tags-menu [bmkp-file-this-dir-all-tags-regexp-jump-other-window] + '(menu-item "File in This Dir, All Tags Matching Regexp..." + bmkp-file-this-dir-all-tags-regexp-jump-other-window + :help "Jump to a file bookmark in this dir where each tag matches a regexp")) +(define-key bmkp-jump-tags-menu [bmkp-file-this-dir-some-tags-regexp-jump-other-window] + '(menu-item "File in This Dir, Any Tag Matching Regexp..." + bmkp-file-this-dir-some-tags-regexp-jump-other-window + :help "Jump to a file bookmark in this dir where at least one tag matches a regexp")) +(define-key bmkp-jump-tags-menu [bmkp-file-this-dir-all-tags-jump-other-window] + '(menu-item "File in This Dir, All Tags in Set..." bmkp-file-this-dir-all-tags-jump-other-window + :help "Jump to a file bookmark in this dir that has all of a set of tags that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-file-this-dir-some-tags-jump-other-window] + '(menu-item "File in This Dir, Any Tag in Set..." bmkp-file-this-dir-some-tags-jump-other-window + :help "Jump to a file bookmark in this dir that has some of a set of tags that you enter")) + +(define-key bmkp-jump-tags-menu [jump-sep5] '("--")) ;---------------------------------------------- +(define-key bmkp-jump-tags-menu [bmkp-file-all-tags-regexp-jump-other-window] + '(menu-item "File, All Tags Matching Regexp..." bmkp-file-all-tags-regexp-jump-other-window + :help "Jump to a file or dir bookmark where each tag matches a regexp that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-file-some-tags-regexp-jump-other-window] + '(menu-item "File, Any Tag Matching Regexp..." bmkp-file-some-tags-regexp-jump-other-window + :help "Jump to a file or dir bookmark where at least one tag matches a regexp that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-file-all-tags-jump-other-window] + '(menu-item "File, All Tags in Set..." bmkp-file-all-tags-jump-other-window + :help "Jump to a file or dir bookmark that has all of a set of tags that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-file-some-tags-jump-other-window] + '(menu-item "File, Any Tag in Set..." bmkp-file-some-tags-jump-other-window + :help "Jump to a file or dir bookmark that has some of a set of tags that you enter")) + +(define-key bmkp-jump-tags-menu [jump-sep4] '("--")) ;---------------------------------------------- +(define-key bmkp-jump-tags-menu [bmkp-autofile-all-tags-regexp-jump-other-window] + '(menu-item "Autofile, All Tags Matching Regexp..." + bmkp-autofile-all-tags-regexp-jump-other-window + :help "Jump to an autofile bookmark where each tag matches a regexp that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-autofile-some-tags-regexp-jump-other-window] + '(menu-item "Autofile, Any Tag Matching Regexp..." + bmkp-autofile-some-tags-regexp-jump-other-window + :help "Jump to an autofile bookmark where at least one tag matches a regexp that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-autofile-all-tags-jump-other-window] + '(menu-item "Autofile, All Tags in Set..." + bmkp-autofile-all-tags-jump-other-window + :help "Jump to an autofile bookmark that has all of a set of tags that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-autofile-some-tags-jump-other-window] + '(menu-item "Autofile, Any Tag in Set..." bmkp-autofile-some-tags-jump-other-window + :help "Jump to an autofile bookmark that has some of a set of tags that you enter")) + +(when (fboundp 'bmkp-find-file-all-tags) ; Emacs 21+ + (define-key bmkp-jump-tags-menu [jump-sep3] '("--")) ;---------------------------------------------- + (define-key bmkp-jump-tags-menu [bmkp-find-file-all-tags-regexp-other-window] + '(menu-item "Find Autofile, All Tags Matching Regexp..." + bmkp-find-file-all-tags-regexp-other-window + :help "Visit a bookmarked file where each tag matches a regexp that you enter")) + (define-key bmkp-jump-tags-menu [bmkp-find-file-some-tags-regexp-other-window] + '(menu-item "Find Autofile, Any Tag Matching Regexp..." + bmkp-find-file-some-tags-regexp-other-window + :help "Visit a bookmarked file where at least one tag matches a regexp that you enter")) + (define-key bmkp-jump-tags-menu [bmkp-find-file-all-tags-other-window] + '(menu-item "Find Autofile, All Tags in Set..." + bmkp-find-file-all-tags-other-window + :help "Visit a bookmarked file that has all of a set of tags that you enter")) + (define-key bmkp-jump-tags-menu [bmkp-find-file-some-tags-other-window] + '(menu-item "Find Autofile, Any Tag in Set..." bmkp-find-file-some-tags-other-window + :help "Visit a bookmarked file that has some of a set of tags that you enter"))) + +(define-key bmkp-jump-tags-menu [jump-sep2] '("--")) ;---------------------------------------------- +(define-key bmkp-jump-tags-menu [bmkp-all-tags-regexp-jump-other-window] + '(menu-item "All Tags Matching Regexp..." bmkp-all-tags-regexp-jump-other-window + :help "Jump to a bookmark that has each tag matching a regexp that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-some-tags-regexp-jump-other-window] + '(menu-item "Any Tag Matching Regexp..." bmkp-some-tags-regexp-jump-other-window + :help "Jump to a bookmark that has at least one tag matching a regexp that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-all-tags-jump-other-window] + '(menu-item "All Tags in Set..." bmkp-all-tags-jump-other-window + :help "Jump to a bookmark that has all of a set of tags that you enter")) +(define-key bmkp-jump-tags-menu [bmkp-some-tags-jump-other-window] + '(menu-item "Any Tag in Set..." bmkp-some-tags-jump-other-window + :help "Jump to a bookmark that has some of a set of tags that you enter")) + + +;; `File' > `Find File or Autofile' submenu +;; or, for Emacs 20-21, single item `File' > `Find File or Autofile...'. +(if (not (fboundp 'bmkp-find-file-all-tags)) + (define-key menu-bar-file-menu [bmkp-find-file-other-window] ; Emacs 20-21 + '(menu-item "Find File or Autofile..." bmkp-find-file-other-window)) + (defvar bmkp-find-file-menu (make-sparse-keymap) + "`Find File or Autofile' submenu for menu-bar `File' menu.") + (define-key menu-bar-file-menu [bmkp-find-file-menu] + (list 'menu-item "Find File or Autofile" bmkp-find-file-menu)) + (define-key bmkp-find-file-menu [bmkp-find-file-all-tags-regexp-other-window] + '(menu-item "All Tags Matching Regexp..." bmkp-find-file-all-tags-regexp-other-window + :help "Visit a file or dir where each tag matches a regexp that you enter")) + (define-key bmkp-find-file-menu [bmkp-find-file-some-tags-regexp-other-window] + '(menu-item "Any Tag Matching Regexp..." bmkp-find-file-some-tags-regexp-other-window + :help "Jump to a file or dir bookmark where at least one tag matches a regexp that you enter")) + (define-key bmkp-find-file-menu [bmkp-find-file-all-tags-other-window] + '(menu-item "All Tags in Set..." bmkp-find-file-all-tags-other-window + :help "Visit a file or dir that has all of a set of tags that you enter")) + (define-key bmkp-find-file-menu [bmkp-find-file-some-tags-other-window] + '(menu-item "Any Tag in Set..." bmkp-find-file-some-tags-other-window + :help "Visit a file or dir that has some of a set of tags that you enter")) + (define-key bmkp-find-file-menu [find-file-sep2] '("--")) ;--------- + (define-key bmkp-find-file-menu [bmkp-find-file-other-window] + '(menu-item "Any File or Autofile..." bmkp-find-file-other-window + :help "Visit a bookmarked file or directory: an autofile bookmark."))) + +;;;;;;;;;;;;;;;;;;;;; + +(provide 'bookmark+-key) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-key.el ends here diff --git a/lisp/bookmark+-lit.el b/lisp/bookmark+-lit.el new file mode 100644 index 00000000..9149688e --- /dev/null +++ b/lisp/bookmark+-lit.el @@ -0,0 +1,1541 @@ +;;; bookmark+-lit.el --- Bookmark highlighting for Bookmark+. +;; +;; Filename: bookmark+-lit.el +;; Description: Bookmark highlighting for Bookmark+. +;; Author: Drew Adams +;; Maintainer: Drew Adams +;; Copyright (C) 2010-2022, Drew Adams, all rights reserved. +;; Created: Wed Jun 23 07:49:32 2010 (-0700) +;; Last-Updated: Fri Jan 14 12:50:59 2022 (-0800) +;; By: dradams +;; Update #: 1005 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-lit.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, highlighting, bookmark+ +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; `bookmark', `pp', `pp+'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Bookmark highlighting for Bookmark+ (library `bookmark+.el'). +;; +;; The Bookmark+ libraries are: +;; +;; `bookmark+.el' - main code library +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit.el' - code for highlighting bookmarks (this file) +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' +;; `bookmark+-1.el' - other required code (non-bmenu) +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc.el' - documentation (comment-only file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; This library (`bookmark+-lit.el') is a Bookmark+ option. If you +;; want to use it then load it before loading `bookmark+.el', so +;; that its commands can be bound to keys and menu items. +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you have library +;; `bookmark+-doc.el' in your `load-path'.) + +;;(@> "Index") +;; +;; Index +;; ----- +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "Things Defined Here") +;; (@> "Faces (Customizable)") +;; (@> "User Options (Customizable)") +;; (@> "Internal Variables") +;; (@> "Functions") +;; (@> "Menu-List (`*-bmenu-*') Commands") +;; (@> "General Highlight Commands") +;; (@> "Other Functions") + +;;(@* "Things Defined Here") +;; +;; Things Defined Here +;; ------------------- +;; +;; Commands defined here: +;; +;; +;; `bmkp-bmenu-light', `bmkp-bmenu-light-marked', +;; `bmkp-bmenu-set-lighting', `bmkp-bmenu-set-lighting-for-marked', +;; `bmkp-bmenu-show-only-lighted-bookmarks', `bmkp-bmenu-unlight', +;; `bmkp-bmenu-unlight-marked', `bmkp-bookmarks-lighted-at-point', +;; `bmkp-cycle-lighted-this-buffer', +;; `bmkp-cycle-lighted-this-buffer-other-window', +;; `bmkp-describe-bookmark-lighted-here', +;; `bmkp-light-autonamed-this-buffer', `bmkp-light-bookmark', +;; `bmkp-light-bookmark-this-buffer', `bmkp-light-bookmarks', +;; `bmkp-light-bookmarks-in-region', +;; `bmkp-light-navlist-bookmarks', +;; `bmkp-light-non-autonamed-this-buffer', +;; `bmkp-light-this-buffer', `bmkp-lighted-jump', +;; `bmkp-lighted-jump-other-window', `bmkp-lighted-jump-to-list', +;; `bmkp-next-lighted-this-buffer', +;; `bmkp-next-lighted-this-buffer-repeat', +;; `bmkp-previous-lighted-this-buffer', +;; `bmkp-previous-lighted-this-buffer-repeat', +;; `bmkp-set-lighting-for-bookmark', +;; `bmkp-set-lighting-for-buffer', +;; `bmkp-set-lighting-for-this-buffer', +;; `bmkp-toggle-auto-light-when-jump', +;; `bmkp-toggle-auto-light-when-set', +;; `bmkp-unlight-autonamed-this-buffer', `bmkp-unlight-bookmark', +;; `bmkp-unlight-bookmark-here', +;; `bmkp-unlight-bookmark-this-buffer', `bmkp-unlight-bookmarks', +;; `bmkp-unlight-non-autonamed-this-buffer', +;; `bmkp-unlight-this-buffer'. +;; +;; User options defined here: +;; +;; `bmkp-auto-light-relocate-when-jump-flag', +;; `bmkp-auto-light-when-jump', `bmkp-auto-light-when-set', +;; `bmkp-light-left-fringe-bitmap' (Emacs 22+), +;; `bmkp-light-priorities', `bmkp-light-right-fringe-bitmap' (Emacs +;; 22+), `bmkp-light-style-autonamed', +;; `bmkp-light-style-non-autonamed', `bmkp-light-threshold', +;; `bmkp-tooltip-content-function'. +;; +;; Faces defined here: +;; +;; `bmkp-light-autonamed', `bmkp-light-fringe-autonamed' (Emacs +;; 22+), `bmkp-light-fringe-non-autonamed' (Emacs 22+), +;; `bmkp-light-mark', `bmkp-light-non-autonamed'. +;; +;; Non-interactive functions defined here: +;; +;; `bmkp--pop-to-buffer-same-window', +;; `bmkp-a-bookmark-lighted-at-pos', +;; `bmkp-a-bookmark-lighted-on-this-line', +;; `bmkp-bookmark-data-from-record', +;; `bmkp-bookmark-name-from-record', `bmkp-bookmark-overlay-p', +;; `bmkp-default-lighted', `bmkp-fringe-string' (Emacs 22+), +;; `bmkp-get-lighting', `bmkp-lighted-p', `bmkp-light-face', +;; `bmkp-light-style', `bmkp-light-style-choices', +;; `bmkp-light-when', `bmkp-lighted-alist-only', +;; `bmkp-lighting-attribute', `bmkp-lighting-face', +;; `bmkp-lighting-style', `bmkp-lighting-when', +;; `bmkp-make/move-fringe' (Emacs 22+), +;; `bmkp-make/move-overlay-of-style', `bmkp-number-lighted', +;; `bmkp-overlay-of-bookmark', `bmkp-read-set-lighting-args', +;; `bmkp-set-lighting-for-bookmarks', +;; `bmkp-this-buffer-lighted-alist-only', +;; `bookmark-name-from-full-record', `bookmark-name-from-record'. +;; +;; Internal variables defined here: +;; +;; `bmkp-autonamed-overlays', `bmkp-last-auto-light-when-jump', +;; `bmkp-last-auto-light-when-set', `bmkp-light-styles-alist', +;; `bmkp-non-autonamed-overlays'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;; + +(eval-when-compile (require 'cl)) ;; case (plus, for Emacs 20: push) + +(require 'bookmark) +;; bookmark-alist, bookmark-bmenu-bookmark, bookmark-completing-read, bmkp-get-bookmark, +;; bookmark-get-position, bookmark-handle-bookmark, bookmark-maybe-load-default-file, +;; bookmark-name-from-full-record, bookmark-name-from-record, bookmark-prop-get, bookmark-prop-set + + +;; Some general Renamings. +;; +;; 1. Fix incompatibility introduced by gratuitous Emacs name change. +;; +(cond ((and (fboundp 'bookmark-name-from-record) (not (fboundp 'bookmark-name-from-full-record))) + (defalias 'bookmark-name-from-full-record 'bookmark-name-from-record)) + ((and (fboundp 'bookmark-name-from-full-record) (not (fboundp 'bookmark-name-from-record))) + (defalias 'bookmark-name-from-record 'bookmark-name-from-full-record))) + +;; 2. The vanilla name of the first is misleading, as it returns only the cdr of the record. +;; The second is for consistency. +;; +(defalias 'bmkp-bookmark-data-from-record 'bookmark-get-bookmark-record) +(defalias 'bmkp-bookmark-name-from-record 'bookmark-name-from-full-record) + + +(eval-when-compile + (or (condition-case nil + (load-library "bookmark+-mac") ; Use load-library to ensure latest .elc. + (error nil)) + (require 'bookmark+-mac))) ; Require, so can load separately if not on `load-path'. +;; bmkp-define-show-only-command + + +;; (eval-when-compile (require 'bookmark+-bmu)) +;; bmkp-bmenu-barf-if-not-in-menu-list, bmkp-bmenu-filter-function, +;; bmkp-bmenu-title + +;; (eval-when-compile (require 'bookmark+-1)) +;; bmkp-autonamed-bookmark-p, bmkp-autonamed-this-buffer-alist-only, +;; bmkp-autoname-format, bmkp-current-nav-bookmark, +;; bmkp-current-sort-order, bmkp-cycle-1, bmkp-default-bookmark-name, +;; bmkp-function-bookmark-p, bmkp-get-bookmark-in-alist, bmkp-get-buffer-name, bmkp-jump-1, +;; bmkp-latest-bookmark-alist, bmkp-marked-bookmarks-only, +;; bmkp-msg-about-sort-order, bmkp-nav-alist, bmkp-refresh-menu-list, +;; bmkp-remove-if, bmkp-remove-if-not, bmkp-repeat-command, +;; bmkp-sequence-bookmark-p, bmkp-sort-omit, +;; bmkp-specific-buffers-alist-only, bmkp-this-buffer-alist-only, +;; bmkp-this-file/buffer-cycle-sort-comparer, bmkp-this-buffer-p + +(require 'pp+ nil t) ;; pp-read-expression-map + +;;;;;;;;;;;;;;;;;;;;;;; + +;; Quiet the byte-compiler +;; +(defvar bmkp-autoname-format) ; In `bookmark+-1.el'. +(defvar bmkp-bmenu-buffer) ; In `bookmark+.el' +(defvar bmkp-current-nav-bookmark) ; In `bookmark+-1.el'. +(defvar bmkp-latest-bookmark-alist) ; In `bookmark+-1.el'. +(defvar bmkp-light-left-fringe-bitmap) ; Defined in this file for Emacs 22+. +(defvar bmkp-light-right-fringe-bitmap) ; Defined in this file for Emacs 22+. +(defvar bmkp-nav-alist) ; In `bookmark+-1.el'. +(defvar bmkp-this-file/buffer-cycle-sort-comparer) ; In `bookmark+-1.el'. +(defvar fringe-bitmaps) ; Built-in for Emacs 22+. + + +;;(@* "Faces (Customizable)") +;;; Faces (Customizable) --------------------------------------------- + +(defface bmkp-light-autonamed + '((((background dark)) (:background "#00004AA652F1")) ; a dark cyan + (t (:background "misty rose"))) ; a light pink + "*Face used to highlight an autonamed bookmark (except in the fringe)." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-light-autonamed-region + '((((background dark)) (:background "#22225F5F2222")) ; a dark green + (t (:background "plum"))) ; a light magenta + "*Face used to highlight an autonamed bookmark (except in the fringe)." + :group 'bookmark-plus :group 'faces) + +(when (fboundp 'fringe-columns) + (defface bmkp-light-fringe-autonamed + '((((background dark)) (:background "#B19E6A64B19E")) ; a dark magenta + (t (:background "#691DC8A2691D"))) ; a medium green + "*Face used to highlight an autonamed bookmark in the fringe." + :group 'bookmark-plus :group 'faces) + (defface bmkp-light-fringe-non-autonamed + '((((background dark)) (:background "#691DC8A2691D")) ; a medium green + (t (:foreground "Black" :background "Plum"))) ; a light magenta + "*Face used to highlight a non-autonamed bookmark in the fringe." + :group 'bookmark-plus :group 'faces)) + +(defface bmkp-light-mark '((t (:background "Plum"))) + "*Face used to mark bookmarks with highlight overrides, in bookmark list. +This face must be combinable with face `bmkp-t-mark'." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-light-non-autonamed + '((((background dark)) (:background "#B19E6A64B19E")) ; a dark magenta + (t (:background "DarkSeaGreen1"))) ; a light green + "*Face used to highlight a non-autonamed bookmark (except in the fringe)." + :group 'bookmark-plus :group 'faces) + +(defface bmkp-light-non-autonamed-region + '((((background dark)) (:background "#BFBF1F1F2F2F")) ; a dark red + (t (:background "turquoise"))) + "*Face used to highlight a non-autonamed bookmark (except in the fringe)." + :group 'bookmark-plus :group 'faces) + +;; Emacs bug # prevents making use of a face in a tooltip. +;; +;; (defface bmkp-tooltip-content-face +;; '((((class color)) +;; :background "lightyellow" +;; :foreground "black" +;; :family "Courier") +;; (t +;; :family "Courier")) +;; "Face for mouseover tooltip content for highlighted bookmarks." +;; :group 'bookmark-plus :group 'faces :group 'tooltip) + +;;(@* "User Options (Customizable)") +;;; User Options (Customizable) -------------------------------------- + +;;;###autoload (autoload 'bmkp-auto-light-relocate-when-jump-flag "bookmark+") +(defcustom bmkp-auto-light-relocate-when-jump-flag t + "*Non-nil means highlight the relocated, instead of the recorded, position. +This has an effect only when the highlighting style for the bookmark +is `point'." + :type 'boolean :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-auto-light-when-jump "bookmark+") +(defcustom bmkp-auto-light-when-jump nil + "*Which bookmarks to automatically highlight when jumped to. +NOTE: The values that specify highlighting in the current buffer +highlight bookmarks in the buffer that is current after jumping. If +the bookmark does not really have an associated buffer, for example a +bookmark with a handler such as `w32-browser' that just invokes a +separate, non-Emacs program, then the current buffer after jumping +will be the buffer before jumping." + :type '(choice + (const :tag "Autonamed bookmark" autonamed-bookmark) + (const :tag "Non-autonamed bookmark" non-autonamed-bookmark) + (const :tag "Any bookmark" any-bookmark) + (const :tag "Autonamed bookmarks in buffer" autonamed-in-buffer) + (const :tag "Non-autonamed bookmarks in buffer" non-autonamed-in-buffer) + (const :tag "All bookmarks in buffer" all-in-buffer) + (const :tag "None (no automatic highlighting)" nil)) + :group 'bookmark-plus) + +;; The value is not correct if user customizes `bmkp-auto-light-when-jump' to non-nil. +;; So must compensate in `bmkp-toggle-auto-light-when-jump'. +(defvar bmkp-last-auto-light-when-jump (and (not bmkp-auto-light-when-jump) 'all-in-buffer) + "Last value of `bmkp-auto-light-when-jump'.") + +;;;###autoload (autoload 'bmkp-auto-light-when-set "bookmark+") +(defcustom bmkp-auto-light-when-set nil + "*Which bookmarks to automatically highlight when set." + :type '(choice + (const :tag "Autonamed bookmark" autonamed-bookmark) + (const :tag "Non-autonamed bookmark" non-autonamed-bookmark) + (const :tag "Any bookmark" any-bookmark) + (const :tag "Autonamed bookmarks in buffer" autonamed-in-buffer) + (const :tag "Non-autonamed bookmarks in buffer" non-autonamed-in-buffer) + (const :tag "All bookmarks in buffer" all-in-buffer) + (const :tag "None (no automatic highlighting)" nil)) + :group 'bookmark-plus) + +;; The value is not correct if user customizes `bmkp-auto-light-when-set' to non-nil. +;; So must compensate in `bmkp-toggle-auto-light-when-set'. +(defvar bmkp-last-auto-light-when-set (and (not bmkp-auto-light-when-set) 'all-in-buffer) + "Last value of `bmkp-auto-light-when-set'.") + +;;;###autoload (autoload 'bmkp-light-priorities "bookmark+") +(defcustom bmkp-light-priorities '((bmkp-autonamed-overlays . 160) + (bmkp-non-autonamed-overlays . 150)) + "*Priorities of bookmark highlighting overlay types. +As an idea, `isearch' uses 1000 and 1001." + :group 'bookmark-plus :type '(alist :key-type symbol :value-type integer)) + +;; Not used for Emacs 20-21 or Emacs built without fringe support. +(when (and (fboundp 'fringe-columns) (boundp 'fringe-bitmaps)) + (defcustom bmkp-light-left-fringe-bitmap 'left-triangle + "*Symbol for the left fringe bitmap to use to highlight a bookmark. +This option is not used for Emacs versions before Emacs 22." + :type (cons 'choice (mapcar (lambda (bb) (list 'const bb)) fringe-bitmaps)) + :group 'bookmark-plus) + + ;; Not used for Emacs 20-21 or Emacs built without fringe support. + (defcustom bmkp-light-right-fringe-bitmap 'right-triangle + "*Symbol for the right fringe bitmap to use to highlight a bookmark. +This option is not used for Emacs versions before Emacs 22." + :type (cons 'choice (mapcar (lambda (bb) (list 'const bb)) fringe-bitmaps)) + :group 'bookmark-plus)) + +;; Must be before any options that use it. +(defvar bmkp-light-styles-alist (append '(("Region" . region) + ("Line Beginning" . bol) + ("Position" . point) + ("Line" . line) + ("None" . none)) + (and (fboundp 'fringe-columns) + '(("Left Fringe" . lfringe) + ("Right Fringe" . rfringe) + ("Left Fringe + Line" . line+lfringe) + ("Right Fringe + Line" . line+rfringe)))) + "Alist of highlighting styles. Key: string description. Value: symbol.") + +;; Must be before options that use it. +(defun bmkp-light-style-choices () + "Return custom `:type' used for bookmark highlighting style choices." + (cons 'choice + (mapcar (lambda (xx) (list 'const :tag (car xx) (cdr xx))) bmkp-light-styles-alist))) + +;;;###autoload (autoload 'bmkp-light-style-autonamed "bookmark+") +(defcustom bmkp-light-style-autonamed (if (not (fboundp 'fringe-columns)) ; Emacs 20-21. + 'line + 'line+lfringe) + "*Default highlight style for autonamed bookmarks." + :group 'bookmark-plus :type (bmkp-light-style-choices)) + +;;;###autoload (autoload 'bmkp-light-style-non-autonamed "bookmark+") +(defcustom bmkp-light-style-non-autonamed (if (not (fboundp 'fringe-columns)) ; Emacs 20-21. + 'line + 'line+rfringe) + "*Default highlight style for non-autonamed bookmarks." + :group 'bookmark-plus :type (bmkp-light-style-choices)) + +;;;###autoload (autoload 'bmkp-light-style-autonamed-region "bookmark+") +(defcustom bmkp-light-style-autonamed-region 'region + "*Default highlight style for autonamed region bookmarks." + :group 'bookmark-plus :type (bmkp-light-style-choices)) + +;;;###autoload (autoload 'bmkp-light-style-non-autonamed-region "bookmark+") +(defcustom bmkp-light-style-non-autonamed-region 'region + "*Default highlight style for non-autonamed region bookmarks." + :group 'bookmark-plus :type (bmkp-light-style-choices)) + +;;;###autoload (autoload 'bmkp-light-threshold "bookmark+") +(defcustom bmkp-light-threshold 100000 + "*Maximum number of bookmarks to highlight." + :type 'integer :group 'bookmark-plus) + +;;;###autoload (autoload 'bmkp-tooltip-content-function "bookmark+") +(defcustom bmkp-tooltip-content-function 'bmkp-bookmark-description + "Function providing mouseover tooltip content for highlighted bookmarks. +It should accept a bookmark name or record as its first arg and return +a value acceptable as a `help-echo' property value. + +One alternative to the default value of `bmkp-bookmark-description' is +`bmkp-annotation-or-bookmark-description', which shows the bookmark +annotation if there is one, or the full description if not. + +To prevent showing any tooltip you can use a function, such as +`ignore', that returns nil." + :type 'function :group 'bookmark-plus :group 'tooltip) + +;;(@* "Internal Variables") +;;; Internal Variables ----------------------------------------------- + +(defvar bmkp-autonamed-overlays nil + "Overlays used to highlight autonamed bookmarks.") + +(defvar bmkp-non-autonamed-overlays nil + "Overlays used to highlight non-autonamed bookmarks.") + +;;(@* "Functions") +;;; Functions -------------------------------------------------------- + + +;;(@* "Menu-List (`*-bmenu-*') Commands") +;; *** Menu-List (`*-bmenu-*') Commands *** + +;;;###autoload (autoload 'bmkp-bmenu-show-only-lighted-bookmarks "bookmark+") +(bmkp-define-show-only-command lighted "Display (only) the highlighted bookmarks." ; `H S' in bookmark list + bmkp-lighted-alist-only) + +;;;###autoload (autoload 'bmkp-bmenu-light "bookmark+") +(defun bmkp-bmenu-light () ; `H H' in bookmark list + "Highlight the location of this line's bookmark." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-light-bookmark (bookmark-bmenu-bookmark) nil nil 'MSG)) + +;;;###autoload (autoload 'bmkp-bmenu-light-marked "bookmark+") +(defun bmkp-bmenu-light-marked (&optional parg msgp) ; `H > H' in bookmark list + "Highlight the marked bookmarks." + (interactive (list 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when msgp (message "Highlighting marked bookmarks...")) + (let ((marked (bmkp-marked-bookmarks-only))) + (unless marked (error "No marked bookmarks")) + (dolist (bmk marked) (bmkp-light-bookmark bmk))) + (when msgp (message "Highlighting marked bookmarks...done"))) + +;;;###autoload (autoload 'bmkp-bmenu-unlight "bookmark+") +(defun bmkp-bmenu-unlight () ; `H U' in bookmark list + "Unhighlight the location of this line's bookmark." + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-unlight-bookmark (bookmark-bmenu-bookmark) 'NOERROR)) + +;;;###autoload (autoload 'bmkp-bmenu-unlight-marked "bookmark+") +(defun bmkp-bmenu-unlight-marked (&optional parg msgp) ; `H > U' in bookmark list + "Unhighlight the marked bookmarks." + (interactive (list 'MSG)) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when msgp (message "Unhighlighting marked bookmarks...")) + (let ((marked (bmkp-marked-bookmarks-only))) + (unless marked (error "No marked bookmarks")) + (dolist (bmk marked) (bmkp-unlight-bookmark bmk t))) + (when msgp (message "Unhighlighting marked bookmarks...done"))) + +;;;###autoload (autoload 'bmkp-bmenu-set-lighting "bookmark+") +(defun bmkp-bmenu-set-lighting (style face when &optional msgp) ; `H +' in bookmark list + "Set the `lighting' entry for this line's bookmark. +You are prompted for the highlight STYLE, FACE, and condition (WHEN) +that make up the property-list value of the `lighting' entry." + (interactive + (let* ((bmk (bookmark-bmenu-bookmark)) + (bmk-style (bmkp-lighting-style bmk)) + (bmk-face (bmkp-lighting-face bmk)) + (bmk-when (bmkp-lighting-when bmk))) + (append (bmkp-read-set-lighting-args + (and bmk-style (format "%s" (car (rassq bmk-style bmkp-light-styles-alist)))) + (and bmk-face (format "%S" bmk-face)) + (and bmk-when (format "%S" bmk-when))) + '(MSG)))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (bmkp-set-lighting-for-bookmark (bookmark-bmenu-bookmark) style face when 'MSG)) + +;;;###autoload (autoload 'bmkp-bmenu-set-lighting-for-marked "bookmark+") +(defun bmkp-bmenu-set-lighting-for-marked (style face when &optional msgp) ; `H > +' in bookmark list + "Set the `lighting' entry for the marked bookmarks. +You are prompted for the highlight STYLE, FACE, and condition (WHEN)." + (interactive (append (bmkp-read-set-lighting-args) '(MSG))) + (bmkp-bmenu-barf-if-not-in-menu-list) + (when msgp (message "Setting highlighting...")) + (let ((marked (bmkp-marked-bookmarks-only)) + (curr-bmk (bookmark-bmenu-bookmark))) + (unless marked (error "No marked bookmarks")) + (dolist (bmk marked) + (bookmark-prop-set bmk 'lighting (if (or face style when) + `(,@(and face (not (eq face 'auto)) `(:face ,face)) + ,@(and style (not (eq style 'none)) `(:style ,style)) + ,@(and when (not (eq when 'auto)) `(:when ,when))) + ()))) + (when (get-buffer-create bmkp-bmenu-buffer) (bmkp-refresh-menu-list curr-bmk))) + (when msgp (message "Setting highlighting...done"))) + + +;;(@* "General Highlight Commands") +;; *** General Highlight Commands *** + +;;;###autoload (autoload 'bmkp-bookmarks-lighted-at-point "bookmark+") +(defun bmkp-bookmarks-lighted-at-point (&optional position fullp msgp) ; `C-x p =' + "Return a list of the bookmarks highlighted at point. +Include only those in the current bookmark list (`bookmark-alist'). +With no prefix arg, return the bookmark names. +With a prefix arg, return the full bookmark data. +Interactively, display the info. +Non-interactively: + Use the bookmarks at optional arg POSITION (default: point). + Optional arg FULLP means return full bookmark data. + Optional arg MSGP means display the info." + (interactive (list (point) current-prefix-arg 'MSG)) + (unless position (setq position (point))) + (let ((bmks ()) + bmk) + (dolist (ov (overlays-at position)) + (when (setq bmk (overlay-get ov 'bookmark)) + (when (setq bmk (bmkp-get-bookmark-in-alist bmk 'NOERROR)) ; Ensure it's in current bookmark list. + (push (if fullp bmk (bmkp-bookmark-name-from-record bmk)) bmks)))) + (if (not fullp) + (when msgp (message "%s" bmks)) + (setq bmks (mapcar #'bmkp-get-bookmark bmks)) + (when msgp (pp-eval-expression 'bmks))) + bmks)) + +;;;###autoload (autoload 'bmkp-toggle-auto-light-when-jump "bookmark+") +(defun bmkp-toggle-auto-light-when-jump (&optional msgp) ; Not bound. + "Toggle automatic bookmark highlighting when a bookmark is jumped to. +Set option `bmkp-auto-light-when-jump' to nil if non-nil, and to its +last non-nil value if nil." + (interactive "p") + (when (and bmkp-auto-light-when-jump bmkp-last-auto-light-when-jump) ; Compensate for wrong default + (setq bmkp-last-auto-light-when-jump nil)) + (setq bmkp-last-auto-light-when-jump + (prog1 bmkp-auto-light-when-jump ; Swap + (setq bmkp-auto-light-when-jump bmkp-last-auto-light-when-jump))) + (when msgp (message "Automatic highlighting of bookmarks when jumping is now %s" + (if bmkp-auto-light-when-jump + (upcase (symbol-name bmkp-auto-light-when-jump)) + "OFF")))) + +;;;###autoload (autoload 'bmkp-lighted-jump "bookmark+") +(defun bmkp-lighted-jump (bookmark-name &optional flip-use-region-p) ; `C-x j h' + "Jump to a highlighted bookmark. +This is a specialization of `bookmark-jump' - see that, in particular +for info about using a prefix argument." + (interactive + (let ((alist (bmkp-lighted-alist-only))) + (unless alist (error "No highlighted bookmarks")) + (list (bookmark-completing-read "Jump to highlighted bookmark" nil alist) current-prefix-arg))) + (bmkp-jump-1 bookmark-name 'bmkp--pop-to-buffer-same-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-lighted-jump-other-window "bookmark+") +(defun bmkp-lighted-jump-other-window (bookmark-name &optional flip-use-region-p) ; `C-x 4 j h' + "Jump to a highlighted bookmark in another window. +See `bmkp-lighted-jump'." + (interactive + (let ((alist (bmkp-lighted-alist-only))) + (unless alist (error "No highlighted bookmarks")) + (list (bookmark-completing-read "Jump to highlighted bookmark in another window" nil alist) + current-prefix-arg))) + (bmkp-jump-1 bookmark-name 'bmkp-select-buffer-other-window flip-use-region-p)) + +;;;###autoload (autoload 'bmkp-lighted-jump-to-list "bookmark+") +(defun bmkp-lighted-jump-to-list (bookmark &optional position msgp) ; Not bound. + "Jump to location in `*Bookmark List*' for a lighted bookmark at point. +You are prompted for BOOKMARK (a bookmark name). +Completion candidates are the lighted bookmarks at point." + (interactive (let* ((bmks (bmkp-bookmarks-lighted-at-point (point) nil 'MSG)) + (IGNORE (unless bmks (error "No highlighted bookmarks at point"))) + (bmk (bookmark-completing-read "Bookmark" (car bmks) bmks))) + (list bmk (point) t))) + (pop-to-buffer (get-buffer-create bmkp-bmenu-buffer)) + (bookmark-bmenu-list) + (bmkp-bmenu-goto-bookmark-named (setq bmkp-last-bmenu-bookmark bookmark))) + +;;;###autoload (autoload 'bmkp-unlight-bookmark "bookmark+") +(defun bmkp-unlight-bookmark (bookmark &optional noerrorp msgp) ; Not bound + "Unhighlight BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record." + (interactive + (let ((lighted-bmks (bmkp-lighted-alist-only))) + (unless lighted-bmks (error "No highlighted bookmarks")) + (list (bookmark-completing-read "UNhighlight bookmark" (bmkp-default-lighted) lighted-bmks) + nil + 'MSG))) + (let* ((bmk (bmkp-get-bookmark bookmark 'NOERROR)) + (bmk-name (bmkp-bookmark-name-from-record bmk)) + (autonamedp (and bmk (bmkp-autonamed-bookmark-p bmk)))) + (when bmk ; Skip bad bookmark, but not already highlighted bookmark. + (unless (or noerrorp (bmkp-lighted-p bmk-name)) (error "Bookmark `%s' is not highlighted" bmk-name)) + (dolist (ov (if autonamedp bmkp-autonamed-overlays bmkp-non-autonamed-overlays)) + (when (eq bmk (overlay-get ov 'bookmark)) (delete-overlay ov)))) ; Check full bookmark, not name. + (when msgp (message "UNhighlighted bookmark `%s'" bmk-name)))) + +;;;###autoload (autoload 'bmkp-unlight-bookmark-here "bookmark+") +(defun bmkp-unlight-bookmark-here (&optional noerrorp msgp) ; `C-x p C-u' + "Unhighlight a bookmark at point or the same line (in that order)." + (interactive (list nil 'MSG)) + (let ((bmk (or (bmkp-a-bookmark-lighted-at-pos) (bmkp-a-bookmark-lighted-on-this-line)))) + (unless bmk (error "No highlighted bookmark on this line")) + (bmkp-unlight-bookmark bmk noerrorp msgp))) + +;;;###autoload (autoload 'bmkp-unlight-bookmark-this-buffer "bookmark+") +(defun bmkp-unlight-bookmark-this-buffer (bookmark &optional noerrorp msgp) ; `C-x p u' + "Unhighlight a BOOKMARK in this buffer. +BOOKMARK is a bookmark name or a bookmark record. +With a prefix arg, choose from all lighted bookmarks, not just those +in this buffer." + (interactive + (let ((lighted-bmks (if current-prefix-arg + (bmkp-lighted-alist-only) + (bmkp-this-buffer-lighted-alist-only))) + (msg-suffix (if current-prefix-arg "" " in this buffer"))) + (unless lighted-bmks (error "No highlighted bookmarks%s" msg-suffix)) + (list (bookmark-completing-read (format "UNhighlight bookmark%s in this buffer" msg-suffix) + (bmkp-default-lighted) + lighted-bmks + nil + nil + 'USE-NIL-ALIST-P) + nil + 'MSG))) + (bmkp-unlight-bookmark bookmark noerrorp msgp)) + +;;;###autoload (autoload 'bmkp-unlight-bookmarks "bookmark+") +(defun bmkp-unlight-bookmarks (&optional overlays-symbols this-buffer-p msgp) ; `C-x p U' + "Unhighlight lighted bookmarks. +A prefix argument determines which bookmarks to unhighlight: + none - Current buffer, all lighted bookmarks. + >= 0 - Current buffer, only autonamed lighted bookmarks. + < 0 - Current buffer, only non-autonamed lighted bookmarks. + C-u - All buffers (all lighted bookmarks)." + (interactive (list (cond ((or (not current-prefix-arg) (consp current-prefix-arg)) + '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays)) + ((natnump current-prefix-arg) '(bmkp-autonamed-overlays)) + (current-prefix-arg '(bmkp-non-autonamed-overlays))) + (or (not current-prefix-arg) (atom current-prefix-arg)) + 'MSG)) + (unless overlays-symbols + (setq overlays-symbols '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays))) + (let ((count 0) + (count-auto 0) + (count-non-auto 0) + (this-buf (current-buffer))) + (dolist (ov-symb overlays-symbols) + (dolist (ov (symbol-value ov-symb)) + (let ((ov-buf (overlay-buffer ov))) + (when (and ov-buf (or (not this-buffer-p) (eq ov-buf this-buf))) + (when (eq 'bmkp-autonamed-overlays ov-symb) + (setq count-auto (1+ count-auto) + count (1+ count))) + (when (eq 'bmkp-non-autonamed-overlays ov-symb) + (setq count-non-auto (1+ count-non-auto) + count (1+ count))) + (delete-overlay ov))))) + (when msgp (message "UNhighlighted %d bookmarks %s: %d autonamed, %d other" + count (if this-buffer-p "in this buffer" "(all buffers)") + count-auto count-non-auto)))) + +;;;###autoload (autoload 'bmkp-unlight-autonamed-this-buffer "bookmark+") +(defun bmkp-unlight-autonamed-this-buffer (&optional everywherep) ; Not bound + "Unhighlight autonamed bookmarks. +No prefix arg: unhighlight them only in the current buffer. +Prefix arg, unhighlight them everywhere." + (interactive "P") + (bmkp-unlight-bookmarks '(bmkp-autonamed-overlays) (not everywherep))) + +;;;###autoload (autoload 'bmkp-unlight-non-autonamed-this-buffer "bookmark+") +(defun bmkp-unlight-non-autonamed-this-buffer (&optional everywherep) ; Not bound + "Unhighlight non-autonamed bookmarks. +No prefix arg: unhighlight them only in the current buffer. +Prefix arg, unhighlight them everywhere." + (interactive "P") + (bmkp-unlight-bookmarks '(bmkp-non-autonamed-overlays) (not everywherep))) + +;;;###autoload (autoload 'bmkp-unlight-this-buffer "bookmark+") +(defun bmkp-unlight-this-buffer () ; Not bound + "Unhighlight all bookmarks in the current buffer." + (interactive) + (bmkp-unlight-bookmarks)) + +;;;###autoload (autoload 'bmkp-toggle-auto-light-when-set "bookmark+") +(defun bmkp-toggle-auto-light-when-set (&optional msgp) ; Not bound. + "Toggle automatic bookmark highlighting when a bookmark is set. +Set option `bmkp-auto-light-when-set' to nil if non-nil, and to its +last non-nil value if nil." + (interactive "p") + (when (and bmkp-auto-light-when-set bmkp-last-auto-light-when-set) ; Compensate for wrong default + (setq bmkp-last-auto-light-when-set nil)) + (setq bmkp-last-auto-light-when-set (prog1 bmkp-auto-light-when-set ; Swap + (setq bmkp-auto-light-when-set bmkp-last-auto-light-when-set))) + (when msgp (message "Automatic highlighting of bookmarks when setting is now %s" + (if bmkp-auto-light-when-set + (upcase (symbol-name bmkp-auto-light-when-set)) + "OFF")))) + +;;;###autoload (autoload 'bmkp-set-lighting-for-bookmark "bookmark+") +(defun bmkp-set-lighting-for-bookmark (bookmark-name style face when &optional msgp light-now-p) ; Not bound + "Set the `lighting' entry for bookmark BOOKMARK-NAME. +You are prompted for the bookmark, highlight STYLE, FACE, and +condition (WHEN) that make up the property-list value of the +`lighting' entry. + +With a prefix argument, do not highlight now. + +Non-interactively: +STYLE, FACE, and WHEN are as for a bookmark's `lighting' entry + properties, or nil if no such property. +Non-nil MSGP means display a highlighting progress message. +Non-nil LIGHT-NOW-P means apply the highlighting now." + (interactive + (let* ((bmk (bookmark-completing-read "Highlight bookmark" + (or (bmkp-default-lighted) (bmkp-default-bookmark-name)))) + (bmk-style (bmkp-lighting-style bmk)) + (bmk-face (bmkp-lighting-face bmk)) + (bmk-when (bmkp-lighting-when bmk))) + (append (list bmk) + (bmkp-read-set-lighting-args + (and bmk-style (format "%s" (car (rassq bmk-style bmkp-light-styles-alist)))) + (and bmk-face (format "%S" bmk-face)) + (and bmk-when (format "%S" bmk-when))) + (list 'MSGP (not current-prefix-arg))))) + (when msgp (message "Setting highlighting...")) + (bookmark-prop-set bookmark-name 'lighting (if (or face style when) + `(,@(and face (not (eq face 'auto)) `(:face ,face)) + ,@(and style (not (eq style 'none)) `(:style ,style)) + ,@(and when (not (eq when 'auto)) `(:when ,when))) + ())) + (when (get-buffer-create bmkp-bmenu-buffer) (bmkp-refresh-menu-list bookmark-name)) + (when msgp (message "Setting highlighting...done")) + (when light-now-p (bmkp-light-bookmark bookmark-name nil nil msgp))) ; This msg is more informative. + +;;;###autoload (autoload 'bmkp-set-lighting-for-buffer "bookmark+") +(defun bmkp-set-lighting-for-buffer (buffer style face when &optional msgp light-now-p) ; Not bound + "Set the `lighting' entry for each of the bookmarks for BUFFER. +You are prompted for the highlight STYLE, FACE, and condition (WHEN). +With a prefix argument, do not highlight now. + +Non-interactively: +STYLE, FACE, and WHEN are as for a bookmark's `lighting' entry + properties, or nil if no such property. +Non-nil MSGP means display a highlighting progress message. +Non-nil LIGHT-NOW-P means apply the highlighting now." + (interactive (append (list (bmkp-completing-read-buffer-name)) + (bmkp-read-set-lighting-args) + (list 'MSGP (not current-prefix-arg)))) + (bmkp-set-lighting-for-bookmarks + (let ((bmkp-last-specific-buffer buffer)) (bmkp-last-specific-buffer-alist-only)) + style face when msgp light-now-p)) + +;;;###autoload (autoload 'bmkp-set-lighting-for-this-buffer "bookmark+") +(defun bmkp-set-lighting-for-this-buffer (style face when &optional msgp light-now-p) ; Not bound + "Set the `lighting' entry for each of the bookmarks for this buffer. +You are prompted for the highlight STYLE, FACE, and condition (WHEN). +With a prefix argument, do not highlight now. + +Non-interactively: +STYLE, FACE, and WHEN are as for a bookmark's `lighting' entry + properties, or nil if no such property. +Non-nil MSGP means display a highlighting progress message. +Non-nil LIGHT-NOW-P means apply the highlighting now." + (interactive (append (bmkp-read-set-lighting-args) (list 'MSGP (not current-prefix-arg)))) + (bmkp-set-lighting-for-bookmarks (bmkp-this-buffer-alist-only) style face when msgp light-now-p)) + +(defun bmkp-set-lighting-for-bookmarks (alist style face when &optional msgp light-now-p) + "Set the `lighting' entry for each of the bookmarks in ALIST. +STYLE, FACE, and WHEN are as for a bookmark's `lighting' entry + properties, or nil if no such property. +Non-nil MSGP means display a highlighting progress message. +Non-nil LIGHT-NOW-P means apply the highlighting now." + (when msgp (message "Setting highlighting...")) + (dolist (bmk alist) (bmkp-set-lighting-for-bookmark bmk style face when)) ; No MSGP arg here. + (when msgp (message "Setting highlighting...done")) + (when light-now-p (bmkp-light-bookmarks alist nil msgp))) ; Do separately so we get its message. + +;;;###autoload (autoload 'bmkp-light-bookmark "bookmark+") +(defun bmkp-light-bookmark (bookmark &optional style face msgp pointp) ; Not bound + "Highlight BOOKMARK. +With a prefix arg you are prompted for the style and/or face to use: + Plain prefix arg (`C-u'): prompt for both style and face. + Numeric non-negative arg: prompt for face. + Numeric negative arg: prompt for style. + +Non-interactively: + BOOKMARK is a bookmark name or a bookmark record, or it is ignored. + STYLE and FACE override the defaults. + POINT-P non-nil means highlight point rather than the recorded + bookmark position." + (interactive + (let* ((bmk (bookmark-completing-read "Highlight bookmark" (bmkp-default-bookmark-name))) + (sty (and current-prefix-arg (or (consp current-prefix-arg) + (<= (prefix-numeric-value current-prefix-arg) 0)) + (cdr (assoc (let ((completion-ignore-case t)) + (completing-read + "Style: " bmkp-light-styles-alist nil t nil nil + (and (bmkp-lighting-style bmk) + (format "%s" (car (rassq (bmkp-lighting-style bmk) + bmkp-light-styles-alist)))))) + bmkp-light-styles-alist)))) + (fac (and current-prefix-arg (or (consp current-prefix-arg) + (natnump (prefix-numeric-value current-prefix-arg))) + (not (member sty '(lfringe rfringe none))) ; No face possible for these. + (condition-case nil ; Emacs 22+ accepts a default. + (read-face-name "Face: " (format "%S" (bmkp-lighting-face bmk))) + (wrong-number-of-arguments (read-face-name "Face: ")))))) + (list bmk sty fac 'MSG))) + (let* ((bmkp-use-region nil) ; Inhibit region handling. + (bmk (bmkp-get-bookmark bookmark (not msgp))) ; Error if interactive. + (bmk-name (bmkp-bookmark-name-from-record bmk)) + (pos (and bmk (bookmark-get-position bmk))) + (buf (and bmk (bmkp-get-buffer-name bmk))) + (autonamedp (and bmk (bmkp-autonamed-bookmark-p bmk))) + (styl (or style (and bmk (bmkp-light-style bmk)))) + (fac (or face (and bmk + (not (member styl '(lfringe rfringe none))) + (bmkp-light-face bmk)))) + (passes-when-p (and bmk (or face + style ; Always highlight if changed face or style. + (bmkp-light-when bmk)))) + (nb-lit (bmkp-number-lighted)) + bmk-ov) + (catch 'bmkp-light-bookmark + (when bmk ; Just skip bad bookmark if not interactive. + (cond ((setq bmk-ov (bmkp-overlay-of-bookmark bmk)) ; Already highlighted. + (if (not (or style face)) + (when msgp ; No-op batch. + (error "Already highlighted - use prefix arg to change")) + (when style (bmkp-make/move-overlay-of-style style pos autonamedp bmk bmk-ov)) + (when (and face (not (memq styl '(lfringe rfringe none)))) + (overlay-put bmk-ov 'face face))) + (when msgp (message "%sighlighted bookmark `%s'" (if bmk-ov "H" "UNh") bmk-name))) + (passes-when-p + (save-excursion + + ;; See note in comments of `bmkp-light-bookmarks' - same considerations here. + ;; (let ((bmkp-jump-display-function nil)) (bookmark-handle-bookmark bmk)) + ;; + (with-current-buffer (or (and buf (get-buffer buf)) + (current-buffer)) + + ;; POINTP is non-nil when `bmkp-light-bookmark' is called from + ;; `bookmark--jump-via'. + (when (and pointp bmkp-auto-light-relocate-when-jump-flag) + (setq pos (point))) + (when (and pos (< pos (point-max))) + (let ((ov (bmkp-make/move-overlay-of-style styl pos autonamedp bmk))) + (when ov ; nil means `none' style. + (let ((ovs (if autonamedp + 'bmkp-autonamed-overlays + 'bmkp-non-autonamed-overlays))) + (push ov (symbol-value ovs))) + (when (and (not (bmkp-lighted-p bmk)) + (> (setq nb-lit (1+ nb-lit)) bmkp-light-threshold)) + (setq nb-lit (1- nb-lit)) + (throw 'bmkp-light-bookmark bmk)) + (overlay-put ov 'priority + (or (cdr (assoc (if autonamedp + 'bmkp-autonamed-overlays + 'bmkp-non-autonamed-overlays) + bmkp-light-priorities)) + (apply #'min (mapcar #'cdr bmkp-light-priorities)))) + (unless (memq styl '(lfringe rfringe none)) (overlay-put ov 'face fac)) + (overlay-put ov 'evaporate t) + (overlay-put ov 'category 'bookmark-plus) + (overlay-put ov 'bookmark bmk)) ; Use full bookmark, because name can change. + (when msgp + (message "%sighlighted bookmark `%s'" (if ov "H" "UNh") bmk-name))))))) + (t + (when msgp (message "Bookmark's condition canceled highlighting")))))))) + +;;;###autoload (autoload 'bmkp-light-bookmark-this-buffer "bookmark+") +(defun bmkp-light-bookmark-this-buffer (bookmark &optional style face msgp) ; `C-x p h' + "Highlight a BOOKMARK in the current buffer. +With a prefix arg you are prompted for the style and/or face to use: + Plain prefix arg (`C-u'): prompt for both style and face. + Numeric non-negative arg: prompt for face. + Numeric negative arg: prompt for style. +See `bmkp-light-bookmark' for argument descriptions." + (interactive + (let* ((bmk (bookmark-completing-read "Highlight bookmark" + nil + (bmkp-this-buffer-alist-only) + nil + nil + 'USE-NIL-ALIST-P)) + (sty (and current-prefix-arg (or (consp current-prefix-arg) + (<= (prefix-numeric-value current-prefix-arg) 0)) + (cdr (assoc (let ((completion-ignore-case t)) + (completing-read + "Style: " bmkp-light-styles-alist nil t nil nil + (and (bmkp-lighting-style bmk) + (format "%s" (car (rassq (bmkp-lighting-style bmk) + bmkp-light-styles-alist)))))) + bmkp-light-styles-alist)))) + (fac (and current-prefix-arg (or (consp current-prefix-arg) + (natnump (prefix-numeric-value current-prefix-arg))) + (not (member sty '(lfringe rfringe none))) ; No face possible for these. + (condition-case nil ; Emacs 22+ accepts a default. + (read-face-name "Face: " (format "%S" (bmkp-lighting-face bmk))) + (wrong-number-of-arguments (read-face-name "Face: ")))))) + (list bmk sty fac 'MSG))) + (bmkp-light-bookmark bookmark style face msgp)) + +;;;###autoload (autoload 'bmkp-light-bookmarks "bookmark+") +(defun bmkp-light-bookmarks (&optional alist overlays-symbols msgp) ; `C-x p H' + "Highlight bookmarks. +A prefix argument determines which bookmarks to highlight: + none - Current buffer, all bookmarks. + = 0 - Current buffer, highlighted bookmarks only (rehighlight). + > 0 - Current buffer, autonamed bookmarks only. + < 0 - Current buffer, non-autonamed bookmarks only. + C-u - All buffers (all bookmarks) - after confirmation. + C-u C-u - Navlist (all bookmarks). + +Non-interactively, ALIST is the alist of bookmarks to highlight. +It must be provided: if nil then do not highlight any bookmarks." + (interactive + (list (cond ((not current-prefix-arg) (bmkp-this-buffer-alist-only)) + ((consp current-prefix-arg) (if (> (prefix-numeric-value current-prefix-arg) 4) + bmkp-nav-alist + (unless (y-or-n-p + "Confirm highlighting bookmarks in ALL buffers ") + (error "Canceled highlighting")) + (bmkp-specific-buffers-alist-only + (mapcar #'buffer-name (buffer-list))))) + ((> current-prefix-arg 0) (bmkp-autonamed-this-buffer-alist-only)) + ((< current-prefix-arg 0) (bmkp-remove-if #'bmkp-autonamed-bookmark-p + (bmkp-this-buffer-alist-only))) + ((= current-prefix-arg 0) (bmkp-this-buffer-lighted-alist-only))) + (cond ((or (not current-prefix-arg) (consp current-prefix-arg)) + '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays)) + ((natnump current-prefix-arg) '(bmkp-autonamed-overlays)) + (current-prefix-arg '(bmkp-non-autonamed-overlays))) + 'MSG)) + (unless overlays-symbols + (setq overlays-symbols '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays))) + (let ((bmkp-use-region nil) ; Inhibit region handling. + (total 0) + (nb-auto 0) + (nb-non-auto 0) + (new-auto 0) + (new-non-auto 0) + (nb-lit (bmkp-number-lighted)) + bmk bmk-name autonamedp face style pos buf bmk-ov passes-when-p) + (catch 'bmkp-light-bookmarks + (dolist (bookmark alist) + (setq bmk (bmkp-get-bookmark bookmark 'NOERROR) ; Should be a no-op. + bmk-name (and bmk (bmkp-bookmark-name-from-record bmk)) + autonamedp (and bmk (bmkp-autonamed-bookmark-p bmk-name)) + face (and bmk (bmkp-light-face bmk)) + style (and bmk (bmkp-light-style bmk)) + bmk-ov (bmkp-overlay-of-bookmark bmk) + passes-when-p (and bmk (or bmk-ov ; Always highlight if already highlighted. + (bmkp-light-when bmk)))) + (when (and bmk passes-when-p) ; Skip bad bookmark and respect `:when' (unless highlighted). + (setq pos (bookmark-get-position bmk) + buf (bmkp-get-buffer-name bmk)) + (save-excursion + ;; An alternative here would be to call the handler and let it do the highlighting. + ;; In that case, we would need at least to bind the display function to nil while + ;; handling, so we don't also do the jump. In particular, we don't want to pop to + ;; the bookmark in a new window or frame. + ;; Calling the handler would be good for some cases, such as Info, where the + ;; highlighting is not really specific to the buffer but to a narrowed part of it. + ;; + ;; (let ((bmkp-jump-display-function nil)) (bookmark-handle-bookmark bmk)) + ;; + ;; But calling the handler is in general the wrong thing. We don't want highlighting + ;; all Dired bookmarks in a given directory to also do all the file marking and + ;; subdir hiding associated with each of the bookmarks. So we do just the + ;; highlighting, no handling, putting the code in side `with-current-buffer'. + (with-current-buffer (or (and buf (get-buffer buf)) + (current-buffer)) + (when (and pos (< pos (point-max))) + (dolist (ov-symb overlays-symbols) + (when (or (and (eq 'bmkp-autonamed-overlays ov-symb) autonamedp) + (and (eq 'bmkp-non-autonamed-overlays ov-symb) (not autonamedp))) + (let ((ov (bmkp-make/move-overlay-of-style style pos autonamedp bmk bmk-ov))) + (when ov ; nil means `none' style. + (add-to-list ov-symb ov) + (when (eq 'bmkp-autonamed-overlays ov-symb) + (unless bmk-ov (setq new-auto (1+ new-auto))) + (setq nb-auto (1+ nb-auto))) + (when (eq 'bmkp-non-autonamed-overlays ov-symb) + (unless bmk-ov (setq new-non-auto (1+ new-non-auto))) + (setq nb-non-auto (1+ nb-non-auto))) + (when (and (not bmk-ov) (> (setq nb-lit (1+ nb-lit)) bmkp-light-threshold)) + (setq nb-lit (1- nb-lit)) + (throw 'bmkp-light-bookmarks bmk)) + (setq total (1+ total)) + (overlay-put ov 'priority ; > ediff's 100+, < isearch-overlay's 1001. + (or (cdr (assoc ov-symb bmkp-light-priorities)) + (apply #'min (mapcar #'cdr bmkp-light-priorities)))) + (unless (memq style '(lfringe rfringe none)) (overlay-put ov 'face face)) + (overlay-put ov 'evaporate t) + (overlay-put ov 'category 'bookmark-plus) + (overlay-put ov 'bookmark bmk))))))))))) ; Use full bookmark - name can change. + (when msgp (message "%s New: %d auto + %d other, Total: %d auto + %d other = %d" + (if (consp current-prefix-arg) + (if (> (prefix-numeric-value current-prefix-arg) 4) + "[Navlist]" + "[All buffers]") + "[This buffer]") + new-auto new-non-auto nb-auto nb-non-auto total)))) + +;;;###autoload (autoload 'bmkp-light-navlist-bookmarks "bookmark+") +(defun bmkp-light-navlist-bookmarks (&optional overlays-symbols msgp) ; Not bound + "Highlight bookmarks in the navigation list. +No prefix arg: all bookmarks. +Prefix arg >= 0: autonamed bookmarks only. +Prefix arg < 0: non-autonamed bookmarks only." + (interactive + (list (cond ((not current-prefix-arg) '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays)) + ((natnump (prefix-numeric-value current-prefix-arg)) '(bmkp-autonamed-overlays)) + (current-prefix-arg '(bmkp-non-autonamed-overlays))) + 'MSG)) + (bmkp-light-bookmarks bmkp-nav-alist overlays-symbols msgp)) + +;;;###autoload (autoload 'bmkp-light-this-buffer "bookmark+") +(defun bmkp-light-this-buffer (&optional overlays-symbols msgp) ; Not bound + "Highlight bookmarks in the current buffer. +No prefix arg: all bookmarks. +Prefix arg >= 0: autonamed bookmarks only. +Prefix arg < 0: non-autonamed bookmarks only." + (interactive + (list (cond ((not current-prefix-arg) '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays)) + ((natnump (prefix-numeric-value current-prefix-arg)) '(bmkp-autonamed-overlays)) + (current-prefix-arg '(bmkp-non-autonamed-overlays))) + 'MSG)) + (bmkp-light-bookmarks (bmkp-this-buffer-alist-only) overlays-symbols msgp)) + +;;;###autoload (autoload 'bmkp-light-bookmarks-in-region "bookmark+") +(defun bmkp-light-bookmarks-in-region (start end &optional overlays-symbols msgp) ; Not bound + "Highlight bookmarks in the region. +No prefix arg: all bookmarks. +Prefix arg >= 0: autonamed bookmarks only. +Prefix arg < 0: non-autonamed bookmarks only." + (interactive + (list (region-beginning) + (region-end) + (cond ((not current-prefix-arg) '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays)) + ((natnump (prefix-numeric-value current-prefix-arg)) '(bmkp-autonamed-overlays)) + (current-prefix-arg '(bmkp-non-autonamed-overlays))) + 'MSG)) + (bmkp-light-bookmarks (bmkp-remove-if-not (lambda (bmk) (let ((pos (bookmark-get-position bmk))) + (and (>= pos start) (<= pos end)))) + (bmkp-this-buffer-alist-only)) + overlays-symbols msgp)) + +;;;###autoload (autoload 'bmkp-light-autonamed-this-buffer "bookmark+") +(defun bmkp-light-autonamed-this-buffer (&optional msgp) ; Not bound + "Highlight all autonamed bookmarks." + (interactive (list 'MSG)) + (bmkp-light-bookmarks (bmkp-autonamed-this-buffer-alist-only) '(bmkp-autonamed-overlays) msgp)) + +;;;###autoload (autoload 'bmkp-light-non-autonamed-this-buffer "bookmark+") +(defun bmkp-light-non-autonamed-this-buffer (&optional msgp) ; Not bound + "Highlight all non-autonamed bookmarks." + (interactive (list 'MSG)) + (bmkp-light-bookmarks (bmkp-remove-if #'bmkp-autonamed-bookmark-p (bmkp-this-buffer-alist-only)) + '(bmkp-non-autonamed-overlays) msgp)) + +;;;###autoload (autoload 'bmkp-cycle-lighted-this-buffer "bookmark+") +(defun bmkp-cycle-lighted-this-buffer (increment &optional other-window startoverp) ; Not bound + "Cycle through highlighted bookmarks in this buffer by INCREMENT. +Positive INCREMENT cycles forward. Negative INCREMENT cycles backward. +Interactively, the prefix arg determines INCREMENT: + Plain `C-u': 1 + otherwise: the numeric prefix arg value + +To change the sort order, you can filter the `*Bookmark List*' to show +only highlighted bookmarks for this buffer, sort the bookmarks there, +and use `\\[bmkp-choose-navlist-from-bookmark-list]', choosing `CURRENT *Bookmark List*' as the +navigation list. + +Then you can cycle the bookmarks using `bookmark-cycle' +\(`\\[bmkp-next-bookmark-repeat]' etc.), instead of `bookmark-cycle-lighted-this-buffer'. + +In Lisp code: + Non-nil OTHER-WINDOW means jump to the bookmark in another window. + Non-nil STARTOVERP means reset `bmkp-current-nav-bookmark' to the + first bookmark in the navlist." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) nil startovr))) + (bookmark-maybe-load-default-file) + (let ((bmkp-sort-comparer bmkp-this-file/buffer-cycle-sort-comparer)) + (setq bmkp-nav-alist (bmkp-sort-omit (bmkp-this-buffer-lighted-alist-only)))) + (unless bmkp-nav-alist (error "No lighted bookmarks for cycling")) + (unless (and bmkp-current-nav-bookmark + (not startoverp) + (bmkp-get-bookmark bmkp-current-nav-bookmark 'NOERROR) + (bmkp-this-buffer-p bmkp-current-nav-bookmark)) ; Exclude desktops etc. + (setq bmkp-current-nav-bookmark (car bmkp-nav-alist))) + (if (bmkp-cycle-1 increment other-window startoverp) + (unless (or (bmkp-sequence-bookmark-p bmkp-current-nav-bookmark) + (bmkp-function-bookmark-p bmkp-current-nav-bookmark)) + (message "Position: %9d, Bookmark: `%s'" (point) (bmkp-bookmark-name-from-record + bmkp-current-nav-bookmark))) + (message "Invalid bookmark: `%s'" (bmkp-bookmark-name-from-record bmkp-current-nav-bookmark)))) + +;;;###autoload (autoload 'bmkp-cycle-lighted-this-buffer-other-window "bookmark+") +(defun bmkp-cycle-lighted-this-buffer-other-window (increment &optional startoverp) ; Not bound + "Same as `bmkp-cycle-lighted-this-buffer' but uses another window." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-lighted-this-buffer increment 'OTHER-WINDOW startoverp)) + +;;;###autoload (autoload 'bmkp-next-lighted-this-buffer "bookmark+") +(defun bmkp-next-lighted-this-buffer (n &optional startoverp) ; Repeatable key (e.g. `S-f2'), not bound + "Jump to the Nth-next highlighted bookmark in the current buffer. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one. +See also `bmkp-cycle-lighted-this-buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-lighted-this-buffer n nil startoverp)) + +;;;###autoload (autoload 'bmkp-previous-lighted-this-buffer "bookmark+") +(defun bmkp-previous-lighted-this-buffer (n &optional startoverp) ; Repeatable key (e.g. `f2'), not bound + "Jump to the Nth-previous highlighted bookmark in the current buffer. +See `bmkp-next-lighted-this-buffer'." + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (bmkp-cycle-lighted-this-buffer (- n) nil startoverp)) + +;;;###autoload (autoload 'bmkp-next-lighted-this-buffer-repeat "bookmark+") +(defun bmkp-next-lighted-this-buffer-repeat (arg) ; `C-x p C-down' + "Jump to the Nth next highlighted bookmark in the current buffer. +This is a repeatable version of `bmkp-next-bookmark-this-buffer'. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one (and no repeat)." + (interactive "P") + (require 'repeat) + (bmkp-repeat-command 'bmkp-next-lighted-this-buffer)) + +;;;###autoload (autoload 'bmkp-previous-lighted-this-buffer-repeat "bookmark+") +(defun bmkp-previous-lighted-this-buffer-repeat (arg) ; `C-x p C-up' + "Jump to the Nth previous highlighted bookmark in the current buffer. +See `bmkp-next-lighted-this-buffer-repeat'." + (interactive "P") + (require 'repeat) + (bmkp-repeat-command 'bmkp-previous-lighted-this-buffer)) + +;;;###autoload (autoload 'bmkp-describe-bookmark-lighted-here "bookmark+") +(defun bmkp-describe-bookmark-lighted-here (&optional position defn) ; `C-x p ?' + "Describe a highlighted bookmark at point or the same line. +If there is more than one highlighted bookmark present then which one +is described is undefined. When multiple highlighted bookmarks are +present you might want to use `\\[bmkp-bookmarks-lighted-at-point]' to see the names of all of the +bookmarks at point, and then use `\\[bmkp-describe-bookmark]' to describe one of them. + +When called from Lisp: + * Use POSITION, not point. + * DEFN corresponds to the prefix arg: non-nil means show show the + internal definition of the bookmark." + (interactive (list (point) current-prefix-arg)) + (let ((bmk (or (bmkp-a-bookmark-lighted-at-pos position 'FULL) + (bmkp-a-bookmark-lighted-on-this-line 'FULL)))) + (unless bmk (error "No highlighted bookmark on this line")) + (bmkp-describe-bookmark bmk defn))) + + +;;(@* "Other Functions") +;; *** Other Functions *** + +(defun bmkp-light-face (bookmark) + "Return the face to use to highlight BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +Returns: + nil if BOOKMARK is not a valid bookmark; + the `:face', if any, specified by BOOKMARK's `lighting' entry; + `bmkp-light-autonamed-region' if an autonamed region bookmark; + `bmkp-light-non-autonamed-region' if a non-autonamed region bookmark; + `bmkp-light-autonamed' if an autonamed non-region bookmark; + `bmkp-light-non-autonamed' otherwise." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (or (bmkp-lighting-face bookmark) + (and bookmark (if (bmkp-region-bookmark-p bookmark) + (if (bmkp-autonamed-bookmark-p bookmark) + 'bmkp-light-autonamed-region + 'bmkp-light-non-autonamed-region) + (if (bmkp-autonamed-bookmark-p bookmark) + 'bmkp-light-autonamed + 'bmkp-light-non-autonamed))))) + +(defun bmkp-light-style (bookmark) + "Return the style to use to highlight BOOKMARK. +BOOKMARK is a bookmark name or a bookmark record. +Returns: + * nil if BOOKMARK is not a valid bookmark; + * the `:style', if any, specified by BOOKMARK's `lighting' entry; + * the value of `bmkp-light-style-autonamed-region' if autonamed and + recording a region + * the value of `bmkp-light-style-non-autonamed-region' if autonamed + and recording a region + * the value of `bmkp-light-style-autonamed' if autonamed and not + recording a region + * the value of `bmkp-light-style-non-autonamed-region' if autonamed + and not recording a region" + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (or (bmkp-lighting-style bookmark) + (and bookmark (if (bmkp-region-bookmark-p bookmark) + (if (bmkp-autonamed-bookmark-p bookmark) + bmkp-light-style-autonamed-region + bmkp-light-style-non-autonamed-region) + (if (bmkp-autonamed-bookmark-p bookmark) + bmkp-light-style-autonamed + bmkp-light-style-non-autonamed))))) + +(defun bmkp-light-when (bookmark) + "Return non-nil if BOOKMARK should be highlighted. +BOOKMARK's `:when' condition is used to determine this. +BOOKMARK is a bookmark name or a bookmark record." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (let ((this-bookmark bookmark) + (this-bookmark-name (bmkp-bookmark-name-from-record bookmark)) + (when-sexp (bmkp-lighting-when bookmark))) + (not (eq :no-light (eval when-sexp))))) + +(defun bmkp-lighting-face (bookmark) + "`:face' specified by BOOKMARK's `lighting', or nil if no `:face' entry. +BOOKMARK is a bookmark name or a bookmark record. + +The `:face' entry is the face (a symbol) used to highlight BOOKMARK. +Alternatively, it can be `auto' or nil, which both mean the same as +having no `:face' entry: do not override automatic face choice." + (bmkp-lighting-attribute bookmark :face)) + +(defun bmkp-lighting-style (bookmark) + "`:style' specified by BOOKMARK's `lighting', or nil if no `:style' entry. +BOOKMARK is a bookmark name or a bookmark record. + +The `:style' entry is the style used to highlight BOOKMARK. +It is a value acceptable for `bmkp-light-style-non-autonamed'. +Alternatively, it can be `auto' or nil, which both mean the same as +having no `:style' entry: do not override automatic style choice." + (bmkp-lighting-attribute bookmark :style)) + +(defun bmkp-lighting-when (bookmark) + "`:when' specified by BOOKMARK's `lighting', or nil if no `:when' entry. +BOOKMARK is a bookmark name or a bookmark record. + +The `:when' entry is a sexp that is eval'd when you try to highlight +BOOKMARK. If the result is the symbol `:no-light', then do not +highlight. Otherwise, highlight. (Note that highlighting happens if +the value is nil or there is no `:when' entry.)" + (bmkp-lighting-attribute bookmark :when)) + +(defun bmkp-lighting-attribute (bookmark attribute) + "ATTRIBUTE specified by BOOKMARK's `lighting', or nil if no such attribute. +BOOKMARK is a bookmark name or a bookmark record. +ATTRIBUTE is `:style' or `:face'." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (let* ((lighting (and bookmark (bmkp-get-lighting bookmark))) + (attr (and (consp lighting) (plist-get lighting attribute)))) + (when (and (eq 'auto attr) (not (eq :when attribute))) + (setq attr nil)) + attr)) + +(defun bmkp-get-lighting (bookmark) + "Return the `lighting' property list for BOOKMARK. +This is the cdr of the `lighting' entry (i.e. the rest of the entry, + with `lighting' removed). +BOOKMARK is a bookmark name or a bookmark record." + (bookmark-prop-get bookmark 'lighting)) + +(defun bmkp-bookmark-overlay-p (overlay) + "Return non-nil if OVERLAY is a bookmark overlay. +The non-nil value returned is in fact the full bookmark." + (and (overlayp overlay) (overlay-get overlay 'bookmark))) + +(defun bmkp-default-lighted () + "Return a highlighted bookmark at point or on this line, or nil if none. +For Emacs 23+, if there is a highlighted bookmark at point, return a + list of all such." + (or (if (> emacs-major-version 22) (bmkp-bookmarks-lighted-at-point) (bmkp-a-bookmark-lighted-at-pos)) + (bmkp-a-bookmark-lighted-on-this-line))) + +(defun bmkp-a-bookmark-lighted-on-this-line (&optional fullp msgp) + "Return a bookmark highlighted on the current line or nil if none. +The search for a highlighted bookmark moves left to bol from point, + then right to eol from point. +Return the bookmark name or, if FULLP non-nil, the full bookmark data." + (let ((pos (point)) + (bol (1+ (line-beginning-position))) + (eol (1- (line-end-position))) + bmk) + (catch 'bmkp-a-bookmark-lighted-on-this-line + (while (>= pos bol) + (when (setq bmk (bmkp-a-bookmark-lighted-at-pos pos)) + (throw 'bmkp-a-bookmark-lighted-on-this-line bmk)) + (setq pos (1- pos))) + (while (<= pos eol) + (when (setq bmk (bmkp-a-bookmark-lighted-at-pos pos)) + (throw 'bmkp-a-bookmark-lighted-on-this-line bmk)) + (setq pos (1+ pos))) + nil) + (when (and bmk fullp) (setq bmk (bmkp-get-bookmark bmk))) + bmk)) + +(defun bmkp-a-bookmark-lighted-at-pos (&optional position fullp) + "Return a bookmark (in current bookmark list) highlighted at POSITION. +Return nil if there is none such. +POSITION defaults to point. +Return the bookmark name or, if FULLP non-nil, the full bookmark data." + (unless position (setq position (point))) + (let (bmk) + (catch 'bmkp-a-bookmark-lighted-at-pos + (dolist (ov (overlays-at position)) + (when (setq bmk (overlay-get ov 'bookmark)) + (throw 'bmkp-a-bookmark-lighted-at-pos bmk))) + nil) + (let ((b-in-list (bmkp-get-bookmark-in-alist bmk 'NOERROR))) + (and b-in-list ; Must be in current bookmark list. + (if fullp b-in-list (bmkp-bookmark-name-from-record bmk)))))) + +(defun bmkp-read-set-lighting-args (&optional default-style default-face default-when) + "Read args STYLE, FACE, and WHEN for commands that set `lighting' prop. +Optional args are the default values (strings) for reading new values." + (let* ((icicle-unpropertize-completion-result-flag t) + (style (cdr (assoc (let ((completion-ignore-case t)) + (completing-read "Style: " bmkp-light-styles-alist + nil t nil nil default-style)) + bmkp-light-styles-alist))) + (face (and (not (member style '(lfringe rfringe none))) ; No face possible for these. + (y-or-n-p "Change face? ") ; Allow nil, for `auto'. + (condition-case nil ; Emacs 22+ accepts a default. + (read-face-name "Face: " default-face) + (wrong-number-of-arguments (read-face-name "Face: "))))) + (when-cands `(("auto" . nil) + ("conditionally (read sexp)") + ("never" . :no-light))) + (when (completing-read "When: " when-cands nil t nil nil + (if default-when "conditionally (read sexp)" "auto"))) + (evald (if (bmkp-string-match-p "^con" when) + (read-from-minibuffer "Highlight when (sexp): " nil + (if (boundp 'pp-read-expression-map) + pp-read-expression-map + read-expression-map) + t 'read-expression-history default-when) + (cdr (assoc when when-cands))))) + (list style face evald))) + +(defun bmkp-lighted-alist-only () + "`bookmark-alist', with only highlighted bookmarks. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) (bmkp-lighted-p bmk)) bookmark-alist)) + +(defun bmkp-this-buffer-lighted-alist-only () + "`bookmark-alist', with only highlighted bookmarks for the current buffer. +A new list is returned (no side effects)." + (bookmark-maybe-load-default-file) + (bmkp-remove-if-not (lambda (bmk) (and (bmkp-this-buffer-p bmk) (bmkp-lighted-p bmk))) + bookmark-alist)) + +(defun bmkp-number-lighted (&optional overlays-symbols) + "Number of bookmarks highlighted." + (unless overlays-symbols + (setq overlays-symbols '(bmkp-autonamed-overlays bmkp-non-autonamed-overlays))) + (let ((count 0)) + (dolist (ov-symb overlays-symbols) + (dolist (ov (symbol-value ov-symb)) (when (overlay-buffer ov) (setq count (1+ count))))) + count)) + +(defalias 'bmkp-lighted-p 'bmkp-overlay-of-bookmark) +(defun bmkp-overlay-of-bookmark (bookmark &optional overlays) + "Return the overlay for BOOKMARK in OVERLAYS, or nil if none. +BOOKMARK is a bookmark name or a bookmark record. +Optional arg OVERLAYS is the list of overlays to check. +If nil, check overlays for both autonamed and non-autonamed bookmarks." + (setq bookmark (bmkp-get-bookmark bookmark 'NOERROR)) + (and bookmark ; Return nil for no such bookmark. + (catch 'bmkp-overlay-of-bookmark + (dolist (ov (if overlays + (apply #'append (mapcar #'symbol-value overlays)) + (append bmkp-autonamed-overlays bmkp-non-autonamed-overlays))) + (when (and (overlay-buffer ov) (eq bookmark (overlay-get ov 'bookmark))) + (throw 'bmkp-overlay-of-bookmark ov))) + nil))) + +(defun bmkp-make/move-overlay-of-style (style pos autonamedp bookmark &optional overlay) + "Return a bookmark overlay of STYLE at position POS for BOOKMARK. +AUTONAMEDP non-nil means the bookmark is autonamed. +Regardless of STYLE, set `help-echo' to the bookmark description. +If OVERLAY is non-nil: + Then it is the overlay to use - change to STYLE and return overlay. + Otherwise, create a new overlay and return it. +If STYLE is `none' then: + If OVERLAY is non-nil, delete it and return nil." + (let ((ov overlay)) + (when (and (< emacs-major-version 22) (not (rassq style bmkp-light-styles-alist))) + (message "Fringe styles not supported before Emacs 22 - changing to `line' style") + (setq style 'line)) + (case style + (region (and (bmkp-region-bookmark-p bookmark) + (let ((end (bmkp-get-end-position bookmark))) + (if (not ov) + (setq ov (make-overlay pos end nil 'FRONT-ADVANCE)) + (move-overlay ov pos end))))) + (line (if (not ov) + (setq ov (save-excursion + (make-overlay + (progn (goto-char pos) (line-beginning-position 1)) + (progn (goto-char pos) (line-beginning-position 2)) + nil + 'FRONT-ADVANCE))) + (overlay-put ov 'before-string nil) ; Remove any fringe highlighting. + (save-excursion + (move-overlay ov + (progn (goto-char pos) (line-beginning-position 1)) + (progn (goto-char pos) (line-beginning-position 2)))))) + (lfringe (setq ov (bmkp-make/move-fringe 'left pos autonamedp ov))) + (rfringe (setq ov (bmkp-make/move-fringe 'right pos autonamedp ov))) + (line+lfringe (setq ov (bmkp-make/move-fringe 'left pos autonamedp ov 'LINEP))) + (line+rfringe (setq ov (bmkp-make/move-fringe 'right pos autonamedp ov 'LINEP))) + (bol (if (not ov) + (setq ov (save-excursion (goto-char pos) + (make-overlay (line-beginning-position) + (1+ (line-beginning-position)) + nil + 'FRONT-ADVANCE))) + (overlay-put ov 'before-string nil) ; Remove any fringe highlighting. + (save-excursion (goto-char pos) + (move-overlay ov (line-beginning-position) + (1+ (line-beginning-position)))))) + (point (if (not ov) + (setq ov (make-overlay pos (1+ pos) nil 'FRONT-ADVANCE)) + (overlay-put ov 'before-string nil) ; Remove any fringe highlighting. + (move-overlay ov pos (1+ pos)))) + (none (when ov (delete-overlay ov)) (setq ov nil))) + + ;; Emacs bug # prevents making use of a face in a `help-echo' tooltip. + ;; (when ov (overlay-put ov 'help-echo (bmkp-propertize (funcall bmkp-tooltip-content-function bookmark) + ;; 'face 'bmkp-tooltip-content-face))) + (when ov (overlay-put ov 'help-echo (funcall bmkp-tooltip-content-function bookmark))) + ov)) + +;; Not used for Emacs 20-21. +(defun bmkp-make/move-fringe (side pos autonamedp &optional overlay linep) + "Return an overlay that uses the fringe. +If SIDE is `right' then use the right fringe, otherwise left. +POS is the overlay position. +AUTONAMEDP: non-nil means use face `bmkp-light-fringe-autonamed'. + nil means use face `bmkp-light-fringe-non-autonamed'. +If OVERLAY is non-nil it is the overlay to use. + Otherwise, create a new overlay. +Non-nil LINEP means also highlight the line containing POS." + (unless (> emacs-major-version 21) (error "Fringe styles not supported before Emacs 22")) + (let ((ov overlay)) + (if ov + (save-excursion (move-overlay overlay (progn (goto-char pos) + (goto-char (line-beginning-position))) + (1+ (point)))) + (setq ov (save-excursion (make-overlay (progn (goto-char pos) + (goto-char (line-beginning-position))) + (1+ (point)) + nil + 'FRONT-ADVANCE)))) + (overlay-put ov 'before-string (bmkp-fringe-string side autonamedp)) + (if linep + (move-overlay ov (save-excursion (goto-char pos) (line-beginning-position 1)) + (save-excursion (goto-char pos) (line-beginning-position 2))) + (overlay-put ov 'face nil)) ; Remove any non-fringe highlighting. + ov)) + +;; Not used for Emacs 20-21. +(defun bmkp-fringe-string (side autonamedp) + "Return a fringe string for a bookmark overlay. +If SIDE is `right' then use the right fringe, otherwise left. +AUTONAMEDP: non-nil means use face `bmkp-light-fringe-autonamed'. + nil means use face `bmkp-light-fringe-non-autonamed'." + (unless (> emacs-major-version 21) (error "Fringe styles not supported before Emacs 22")) + (let ((fringe-string (copy-sequence (if autonamedp "*AUTO*" "*NONAUTO*")))) + (put-text-property 0 (length fringe-string) + 'display (if (eq side 'right) + (list 'right-fringe + bmkp-light-right-fringe-bitmap + (if autonamedp + 'bmkp-light-fringe-autonamed + 'bmkp-light-fringe-non-autonamed)) + (list 'left-fringe + bmkp-light-left-fringe-bitmap + (if autonamedp + 'bmkp-light-fringe-autonamed + 'bmkp-light-fringe-non-autonamed))) + fringe-string) + fringe-string)) + +;; This is also in `bookmark+-bmu.el', since `bookmark+-lit.el' is loaded first but is optional. +;; +(if (fboundp 'pop-to-buffer-same-window) + (defalias 'bmkp--pop-to-buffer-same-window 'pop-to-buffer-same-window) + (defalias 'bmkp--pop-to-buffer-same-window 'switch-to-buffer)) + + +;;;;;;;;;;;;;;;;;;; + +(provide 'bookmark+-lit) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-lit.el ends here diff --git a/lisp/bookmark+-mac.el b/lisp/bookmark+-mac.el new file mode 100644 index 00000000..7b6745e9 --- /dev/null +++ b/lisp/bookmark+-mac.el @@ -0,0 +1,558 @@ +;;; bookmark+-mac.el --- Macros for Bookmark+. +;; +;; Filename: bookmark+-mac.el +;; Description: Macros for Bookmark+. +;; Author: Drew Adams +;; Maintainer: Drew Adams +;; Copyright (C) 2000-2022, Drew Adams, all rights reserved. +;; Created: Sun Aug 15 11:12:30 2010 (-0700) +;; Last-Updated: Fri Jan 14 12:34:20 2022 (-0800) +;; By: dradams +;; Update #: 223 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b-mac.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+, placeholders, annotations, search, info, url, eww, w3m, gnus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Macros for Bookmark+. +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) library +;; `bookmark+-mac.el' - Lisp macros (this file) +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (bmenu) +;; `bookmark+-1.el' - other (non-bmenu) required code +;; `bookmark+-lit.el' - (optional) code for highlighting bookmarks +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc.el' - documentation (comment-only file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you have library +;; `bookmark+-doc.el' in your `load-path'.) +;; +;; +;; ****** NOTE ****** +;; +;; WHENEVER you update Bookmark+ (i.e., download new versions of +;; Bookmark+ source files), I recommend that you do the +;; following: +;; +;; 1. Delete ALL existing BYTE-COMPILED Bookmark+ files +;; (bookmark+*.elc). +;; 2. Load Bookmark+ (`load-library' or `require'). +;; 3. Byte-compile the source files. +;; +;; In particular, ALWAYS LOAD `bookmark+-mac.el' (not +;; `bookmark+-mac.elc') BEFORE YOU BYTE-COMPILE new versions of +;; the files, in case there have been any changes to Lisp macros +;; (in `bookmark+-mac.el'). +;; +;; (This is standard procedure for Lisp: code that depends on +;; macros needs to be byte-compiled anew after loading the +;; updated macros.) +;; +;; ****************** + +;;(@> "Index") +;; +;; If you have library `linkd.el' and Emacs 22 or later, load +;; `linkd.el' and turn on `linkd-mode' now. It lets you easily +;; navigate around the sections of this doc. Linkd mode will +;; highlight this Index, as well as the cross-references and section +;; headings throughout this file. You can get `linkd.el' here: +;; https://www.emacswiki.org/emacs/download/linkd.el. +;; +;; (@> "Things Defined Here") +;; (@> "Functions") +;; (@> "Macros") + +;;(@* "Things Defined Here") +;; +;; Things Defined Here +;; ------------------- +;; +;; Macros defined here: +;; +;; `bmkp-define-cycle-command', `bmkp-define-history-variables', +;; `bmkp-define-next+prev-cycle-commands', +;; `bmkp-define-show-only-command', `bmkp-define-sort-command', +;; `bmkp-define-file-sort-predicate', `bmkp-menu-bar-make-toggle', +;; `bmkp-with-bookmark-dir', `bmkp-with-help-window', +;; `bmkp-with-output-to-plain-temp-buffer'. +;; +;; Non-interactive functions defined here: +;; +;; `bmkp-bookmark-data-from-record', +;; `bmkp-bookmark-name-from-record', +;; `bmkp-replace-regexp-in-string', `bmkp-types-alist', +;; `bookmark-name-from-full-record', `bookmark-name-from-record'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;; + +(require 'bookmark) +;; bookmark-bmenu-bookmark, bookmark-bmenu-ensure-position, +;; bookmark-bmenu-surreptitiously-rebuild-list, bmkp-get-bookmark, +;; bookmark-get-filename + + +;;(@* "Functions") + +;; Some general Renamings. +;; +;; 1. Fix incompatibility introduced by gratuitous Emacs name change. +;; +(cond ((and (fboundp 'bookmark-name-from-record) (not (fboundp 'bookmark-name-from-full-record))) + (defalias 'bookmark-name-from-full-record 'bookmark-name-from-record)) + ((and (fboundp 'bookmark-name-from-full-record) (not (fboundp 'bookmark-name-from-record))) + (defalias 'bookmark-name-from-record 'bookmark-name-from-full-record))) + +;; 2. The vanilla name of the first is misleading, as it returns only the cdr of the record. +;; The second is for consistency. +;; +(defalias 'bmkp-bookmark-data-from-record 'bookmark-get-bookmark-record) +(defalias 'bmkp-bookmark-name-from-record 'bookmark-name-from-full-record) + + +;; (eval-when-compile (require 'bookmark+-bmu)) +;; bmkp-assoc-delete-all, bmkp-bmenu-barf-if-not-in-menu-list, +;; bmkp-bmenu-goto-bookmark-named, bmkp-sort-orders-alist + +;; (eval-when-compile (require 'bookmark+-1)) +;; bmkp-file-bookmark-p, bmkp-float-time, bmkp-local-file-bookmark-p, +;; bmkp-msg-about-sort-order, bmkp-reverse-sort-p, bmkp-sort-comparer + + +;;; This is also defined in `bookmark+-bmu.el'. It is used here to produce the code for +;;; `bmkp-define-show-only-command' and `bmkp-define-sort-command'. +;;; +(defun bmkp-replace-regexp-in-string (regexp rep string &optional fixedcase literal subexp start) + "Replace all matches for REGEXP with REP in STRING and return STRING." + (if (fboundp 'replace-regexp-in-string) ; Emacs > 20. + (replace-regexp-in-string regexp rep string fixedcase literal subexp start) + (if (string-match regexp string) (replace-match rep nil nil string) string))) ; Emacs 20 + +;;(@* "Macros") + +;;; Macros ----------------------------------------------------------- + +;; Same as `icicle-with-help-window' in `icicles-mac.el'. +;;;###autoload (autoload 'bmkp-with-help-window "bookmark+") +(defmacro bmkp-with-help-window (buffer &rest body) + "`with-help-window', if available; else `with-output-to-temp-buffer'." + (if (fboundp 'with-help-window) + `(with-help-window ,buffer ,@body) + `(with-output-to-temp-buffer ,buffer ,@body))) + +(put 'bmkp-with-help-window 'common-lisp-indent-function '(4 &body)) + + +;;;###autoload (autoload 'bmkp-with-output-to-plain-temp-buffer "bookmark+") +(defmacro bmkp-with-output-to-plain-temp-buffer (buf &rest body) + "Like `with-output-to-temp-buffer', but with no `*Help*' navigation stuff." + `(unwind-protect + (progn + (remove-hook 'temp-buffer-setup-hook 'help-mode-setup) + (remove-hook 'temp-buffer-show-hook 'help-mode-finish) + (with-output-to-temp-buffer ,buf ,@body)) + (add-hook 'temp-buffer-setup-hook 'help-mode-setup) + (add-hook 'temp-buffer-show-hook 'help-mode-finish))) + +(put 'bmkp-with-output-to-plain-temp-buffer 'common-lisp-indent-function '(4 &body)) + + +;;;###autoload (autoload 'bmkp-define-cycle-command "bookmark+") +(defmacro bmkp-define-cycle-command (type &optional otherp) + "Define a cycling command for bookmarks of type TYPE. +Non-nil OTHERP means define a command that cycles in another window." + `(defun ,(intern (format "bmkp-cycle-%s%s" type (if otherp "-other-window" ""))) + (increment &optional startoverp) + ,(if otherp + (format "Same as `bmkp-cycle-%s', but use other window." type) + (format "Cycle through %s bookmarks by INCREMENT (default: 1). +Positive INCREMENT cycles forward. Negative INCREMENT cycles backward. +Interactively, the prefix arg determines INCREMENT: + Plain `C-u': 1 + otherwise: the numeric prefix arg value + +Plain `C-u' also means start over at first bookmark. + +In Lisp code: + Non-nil STARTOVERP means reset `bmkp-current-nav-bookmark' to the + first bookmark in the navlist." type)) + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) + startovr))) + (let ((bmkp-nav-alist (bmkp-sort-omit (,(intern (format "bmkp-%s-alist-only" type)))))) + (bmkp-cycle increment ,otherp startoverp)))) + +;;;###autoload (autoload 'bmkp-define-next+prev-cycle-commands "bookmark+") +(defmacro bmkp-define-next+prev-cycle-commands (type &optional otherp) + "Define `next' and `previous' commands for bookmarks of type TYPE. +Non-nil OTHERP means define a command that cycles in another window." + `(progn + ;; `next' command. + (defun ,(intern (format "bmkp-next-%s-bookmark%s" type (if otherp "-other-window" ""))) + (n &optional startoverp) + ,(if otherp + (format "Same as `bmkp-next-%s-bookmark', but use other window." type) + (format "Jump to the Nth-next %s bookmark. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one. +See also `bmkp-cycle-%s'." type type)) + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (,(intern (format "bmkp-cycle-%s%s" type (if otherp "-other-window" ""))) n startoverp)) + + ;; `previous' command. + (defun ,(intern (format "bmkp-previous-%s-bookmark%s" type (if otherp "-other-window" ""))) + (n &optional startoverp) + ,(if otherp + (format "Same as `bmkp-previous-%s-bookmark', but use other window." type) + (format "Jump to the Nth-previous %s bookmark. +See `bmkp-next-%s-bookmark'." type type)) + (interactive (let ((startovr (consp current-prefix-arg))) + (list (if startovr 1 (prefix-numeric-value current-prefix-arg)) startovr))) + (,(intern (format "bmkp-cycle-%s%s" type (if otherp "-other-window" ""))) + (- n) startoverp)) + + ;; `next' repeating command. + (defun ,(intern (format "bmkp-next-%s-bookmark%s-repeat" + type + (if otherp "-other-window" ""))) + (arg) + ,(if otherp + (format "Same as `bmkp-next-%s-bookmark-repeat', but use other window." type) + (format "Jump to the Nth-next %s bookmark. +This is a repeatable version of `bmkp-next-%s-bookmark'. +N defaults to 1, meaning the next one. +Plain `C-u' means start over at the first one (and no repeat)." type type)) + (interactive "P") + (require 'repeat) + (bmkp-repeat-command + ',(intern (format "bmkp-next-%s-bookmark%s" type (if otherp "-other-window" ""))))) + + ;; `previous repeating command. + (defun ,(intern (format "bmkp-previous-%s-bookmark%s-repeat" + type + (if otherp "-other-window" ""))) + (arg) + ,(if otherp + (format "Same as `bmkp-previous-%s-bookmark-repeat', but use other window." type) + (format "Jump to the Nth-previous %s bookmark. +See `bmkp-next-%s-bookmark-repeat'." type type)) + (interactive "P") + (require 'repeat) + (bmkp-repeat-command + ',(intern (format "bmkp-previous-%s-bookmark%s" type (if otherp "-other-window" ""))))))) + +;; We don't bother making this hygienic. Presumably only the Bookmark+ code will call it. +;;;###autoload (autoload 'bmkp-define-show-only-command "bookmark+") +(defmacro bmkp-define-show-only-command (type doc-string filter-function) + "Define a command to show only bookmarks of TYPE in *Bookmark List*. +TYPE is a short string or symbol describing the type of bookmarks. + +The new command is named `bmkp-bmenu-show-only-TYPED-bookmarks', where +TYPED is TYPE, but with any spaces replaced by hyphens (`-'). +Example: `bmkp-bmenu-show-only-tagged-bookmarks', for TYPE `tagged'. + +DOC-STRING is the doc string of the new command. + +The command shows only the bookmarks allowed by FILTER-FUNCTION. + +In case of error, variables `bmkp-bmenu-filter-function', +`bmkp-bmenu-title', and `bmkp-latest-bookmark-alist' are reset to +their values before the command was invoked." + (unless (stringp type) (setq type (symbol-name type))) + (let* ((type-- (bmkp-replace-regexp-in-string "\\s-+" "-" type)) + (command (intern (format "bmkp-bmenu-show-only-%s-bookmarks" type--)))) + `(progn + (defun ,command () + ,doc-string + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (let ((orig-filter-fn bmkp-bmenu-filter-function) + (orig-title bmkp-bmenu-title) + (orig-latest-alist bmkp-latest-bookmark-alist)) + (condition-case err + (progn (setq bmkp-bmenu-filter-function ',filter-function + bmkp-bmenu-title ,(format "%s Bookmarks" (capitalize type))) + (let ((bookmark-alist (funcall bmkp-bmenu-filter-function))) + (setq bmkp-latest-bookmark-alist bookmark-alist) + (bookmark-bmenu-list 'filteredp)) + (when (interactive-p) + (bmkp-msg-about-sort-order (bmkp-current-sort-order) + ,(format "Only %s bookmarks are shown" type)))) + (error (progn (setq bmkp-bmenu-filter-function orig-filter-fn + bmkp-bmenu-title orig-title + bmkp-latest-bookmark-alist orig-latest-alist) + (error "%s" (error-message-string err)))))))))) + +;;;###autoload (autoload 'bmkp-define-sort-command "bookmark+") +(defmacro bmkp-define-sort-command (sort-order comparer doc-string) + "Define a command to sort bookmarks in the bookmark list by SORT-ORDER. +SORT-ORDER is a short string or symbol describing the sorting method. +Examples: \"by last access time\", \"by bookmark name\". + +The new command is named by replacing any spaces in SORT-ORDER with +hyphens (`-') and then adding the prefix `bmkp-bmenu-sort-'. Example: +`bmkp-bmenu-sort-by-bookmark-name', for SORT-ORDER `by bookmark name'. + +COMPARER compares two bookmarks, returning non-nil if and only if the +first bookmark sorts before the second. It must be acceptable as a +value of `bmkp-sort-comparer'. That is, it is either nil, a +predicate, or a list ((PRED...) FINAL-PRED). See the doc for +`bmkp-sort-comparer'. + +DOC-STRING is the doc string of the new command." + (unless (stringp sort-order) (setq sort-order (symbol-name sort-order))) + (let ((command (intern (concat "bmkp-bmenu-sort-" (bmkp-replace-regexp-in-string + "\\s-+" "-" sort-order))))) + `(progn + (setq bmkp-sort-orders-alist (bmkp-assoc-delete-all ,sort-order (copy-sequence + bmkp-sort-orders-alist))) + (setq bmkp-sort-orders-alist (cons (cons ,sort-order ',comparer) bmkp-sort-orders-alist)) + (defun ,command () + ,(concat doc-string "\nRepeating this command cycles among normal sort, reversed \ +sort, and unsorted.") + (interactive) + (bmkp-bmenu-barf-if-not-in-menu-list) + (cond (;; Not this sort order - make it this sort order. + (not (equal bmkp-sort-comparer ',comparer)) + (setq bmkp-sort-comparer ',comparer + bmkp-reverse-sort-p nil)) + (;; Not this sort order reversed - make it reversed. + (not bmkp-reverse-sort-p) + (setq bmkp-reverse-sort-p t)) + (t;; This sort order reversed. Change to unsorted. + (setq bmkp-sort-comparer nil))) + (message "Sorting...") + (bookmark-bmenu-ensure-position) + (let ((current-bmk (bookmark-bmenu-bookmark))) + (bookmark-bmenu-surreptitiously-rebuild-list) + (when current-bmk ; Should be non-nil, but play safe. + (bmkp-bmenu-goto-bookmark-named current-bmk))) ; Put cursor back on right line. + (when (interactive-p) + (bmkp-msg-about-sort-order + ,sort-order + nil + (cond ((and (not bmkp-reverse-sort-p) + (equal bmkp-sort-comparer ',comparer)) "(Repeat: reverse)") + ((equal bmkp-sort-comparer ',comparer) "(Repeat: unsorted)") + (t "(Repeat: sort)")))))))) + +;;;###autoload (autoload 'bmkp-define-file-sort-predicate "bookmark+") +(defmacro bmkp-define-file-sort-predicate (att-nb) + "Define a predicate for sorting bookmarks by file attribute ATT-NB. +See function `file-attributes' for the meanings of the various file +attribute numbers. + +String attribute values sort alphabetically; numerical values sort +numerically; nil sorts before t. + +For ATT-NB 0 (file type), a file sorts before a symlink, which sorts +before a directory. + +For ATT-NB 2 or 3 (uid, gid), a numerical value sorts before a string +value. + +A bookmark that has file attributes sorts before a bookmark that does +not. A file bookmark sorts before a non-file bookmark. Only local +files are tested for attributes - remote-file bookmarks are treated +here like non-file bookmarks." + `(defun ,(intern (format "bmkp-file-attribute-%d-cp" att-nb)) (b1 b2) + ,(format "Sort file bookmarks by attribute %d. +Sort bookmarks with file attributes before those without attributes +Sort file bookmarks before non-file bookmarks. +Treat remote file bookmarks like non-file bookmarks. + +B1 and B2 are full bookmarks (records) or bookmark names. +If either is a record then it need not belong to `bookmark-alist'." + att-nb) + (setq b1 (bmkp-get-bookmark b1)) + (setq b2 (bmkp-get-bookmark b2)) + (let (a1 a2) + (cond (;; Both are file bookmarks. + (and (bmkp-file-bookmark-p b1) (bmkp-file-bookmark-p b2)) + (setq a1 (file-attributes (bookmark-get-filename b1)) + a2 (file-attributes (bookmark-get-filename b2))) + (cond (;; Both have attributes. + (and a1 a2) + (setq a1 (nth ,att-nb a1) + a2 (nth ,att-nb a2)) + ;; Convert times and maybe inode number to floats. + ;; The inode conversion is kludgy, but is probably OK in practice. + (when (consp a1) (setq a1 (bmkp-float-time a1))) + (when (consp a2) (setq a2 (bmkp-float-time a2))) + (cond (;; (1) links, (2) maybe uid, (3) maybe gid, (4, 5, 6) times + ;; (7) size, (10) inode, (11) device. + (numberp a1) + (cond ((< a1 a2) '(t)) + ((> a1 a2) '(nil)) + (t nil))) + ((= 0 ,att-nb) ; (0) file (nil) < symlink (string) < dir (t) + (cond ((and a2 (not a1)) '(t)) ; file vs (symlink or dir) + ((and a1 (not a2)) '(nil)) + ((and (eq t a2) (not (eq t a1))) '(t)) ; symlink vs dir + ((and (eq t a1) (not (eq t a2))) '(t)) + ((and (stringp a1) (stringp a2)) + (if (string< a1 a2) '(t) '(nil))) + (t nil))) + ((stringp a1) ; (2, 3) string uid/gid, (8) modes + (cond ((string< a1 a2) '(t)) + ((string< a2 a1) '(nil)) + (t nil))) + ((eq ,att-nb 9) ; (9) gid would change if re-created. nil < t + (cond ((and a2 (not a1)) '(t)) + ((and a1 (not a2)) '(nil)) + (t nil))))) + (;; First has attributes, but not second. + a1 + '(t)) + (;; Second has attributes, but not first. + a2 + '(nil)) + (;; Neither has attributes. + t + nil))) + (;; First is a file, second is not. + (bmkp-local-file-bookmark-p b1) + '(t)) + (;; Second is a file, first is not. + (bmkp-local-file-bookmark-p b2) + '(nil)) + (t;; Neither is a file. + nil))))) + +;;; This is also defined in `bookmark+-1.el'. It is used here to produce the code for +;;; `bmkp-define-history-variables' and `bmkp-define-sort-command'. +;;; +(defun bmkp-types-alist () + "Alist of bookmark types used by `bmkp-jump-to-type'. +Keys are bookmark type names. Values are corresponding history variables. +The alist is used in commands such as `bmkp-jump-to-type'." + (let ((entries ())) + (mapatoms + (lambda (sym) + (let ((name (symbol-name sym))) + (when (string-match "\\`bmkp-\\(.+\\)-alist-only\\'" name) + (push (cons (match-string 1 name) + (intern (format "bmkp-%s-history" (match-string 1 name)))) + entries))))) + entries)) + +;; Macro that defines Bookmark+ history variables. +;; Use this after you define any new filter function, `bmkp-*-alist-only', +;; for a new kind of bookmark. +;; +;;;###autoload (autoload 'bmkp-define-history-variables "bookmark+") +(defmacro bmkp-define-history-variables () + "Create and eval defvars for Bookmark+ history variables. +The variables are the cdrs of `bmkp-types-alist'. They are used in +commands such as `bmkp-jump-to-type'." + (dolist (entry (bmkp-types-alist)) + `(defvar,(cdr entry) () + ,(format "History for %s bookmarks." (car entry))))) + +;; This is compatible with Emacs 20 and later. +;;;###autoload (autoload 'bmkp-menu-bar-make-toggle "bookmark+") +(defmacro bmkp-menu-bar-make-toggle (command variable item-name message help + &optional setting-sexp &rest keywords) + "Define a menu-bar toggle command. +COMMAND (a symbol) is the toggle command to define. +VARIABLE (a symbol) is the variable to set. +ITEM-NAME (a string) is the menu-item name. +MESSAGE is a format string for the toggle message, with %s for the new + status. +HELP (a string) is the `:help' tooltip text and the doc string first + line (minus final period) for the command. +SETTING-SEXP is a Lisp sexp that sets VARIABLE, or it is nil meaning + set it according to its `defcustom' or using `set-default'. +KEYWORDS is a plist for `menu-item' for keywords other than `:help'." + `(progn + (defun ,command (&optional interactively) + ,(concat help ". +In an interactive call, record this option as a candidate for saving +by \"Save Options\" in Custom buffers.") + (interactive "p") + (if ,(if setting-sexp + `,setting-sexp + `(progn + (custom-load-symbol ',variable) + (let ((set (or (get ',variable 'custom-set) 'set-default)) + (get (or (get ',variable 'custom-get) 'default-value))) + (funcall set ',variable (not (funcall get ',variable)))))) + (message ,message "enabled globally") + (message ,message "disabled globally")) + ;; `customize-mark-as-set' must only be called when a variable is set interactively, + ;; because the purpose is to mark the variable as a candidate for `Save Options', and we + ;; do not want to save options that the user has already set explicitly in the init file. + (when (and interactively (fboundp 'customize-mark-as-set)) + (customize-mark-as-set ',variable))) + '(menu-item ,item-name ,command + :help ,help + :button (:toggle . (and (default-boundp ',variable) (default-value ',variable))) + ,@keywords))) + +;;; Not used currently. Provided so you can use it in your own code, if appropriate. +;;;###autoload (autoload 'bmkp-with-bookmark-dir "bookmark+") +(defmacro bmkp-with-bookmark-dir (bookmark &rest body) + "Evaluate BODY forms with BOOKMARK location as `default-directory'. +If BOOKMARK has no location then use nil as `default-directory'." + `(let* ((loc (bookmark-location ,bookmark)) + (default-directory (and (stringp loc) (not (member loc (list bmkp-non-file-filename + "-- Unknown location --"))) + (if (file-directory-p loc) loc (file-name-directory loc))))) + ,@body)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'bookmark+-mac) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+-mac.el ends here diff --git a/lisp/bookmark+.el b/lisp/bookmark+.el new file mode 100644 index 00000000..690d4edb --- /dev/null +++ b/lisp/bookmark+.el @@ -0,0 +1,243 @@ +;;; bookmark+.el --- Bookmark+: extensions to standard library `bookmark.el'. +;; +;; Filename: bookmark+.el +;; Description: Bookmark+: extensions to standard library `bookmark.el'. +;; Author: Drew Adams, Thierry Volpiatto +;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com") +;; Copyright (C) 2000-2022, Drew Adams, all rights reserved. +;; Copyright (C) 2009, Thierry Volpiatto, all rights reserved. +;; Created: Fri Sep 15 07:58:41 2000 +;; Version: 2021.09.19 +;; Last-Updated: Fri Jan 14 12:52:46 2022 (-0800) +;; By: dradams +;; Update #: 15072 +;; URL: https://www.emacswiki.org/emacs/download/bookmark%2b.el +;; Doc URL: https://www.emacswiki.org/emacs/BookmarkPlus +;; Keywords: bookmarks, bookmark+, projects, placeholders, annotations, search, info, url, eww, w3m, gnus +;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x, 24.x, 25.x, 26.x +;; +;; Features that might be required by this library: +;; +;; `apropos', `apropos+', `avoid', `backquote', `bookmark', +;; `bookmark+', `bookmark+-1', `bookmark+-bmu', `bookmark+-key', +;; `bookmark+-lit', `button', `bytecomp', `cconv', `cl', `cl-lib', +;; `cmds-menu', `col-highlight', `crosshairs', `fit-frame', +;; `font-lock', `font-lock+', `frame-fns', `gv', `help+', +;; `help-fns', `help-fns+', `help-macro', `help-macro+', +;; `help-mode', `hl-line', `hl-line+', `info', `info+', `kmacro', +;; `macroexp', `menu-bar', `menu-bar+', `misc-cmds', `misc-fns', +;; `naked', `pp', `pp+', `radix-tree', `rect', `replace', +;; `second-sel', `strings', `syntax', `text-mode', `thingatpt', +;; `thingatpt+', `vline', `w32browser-dlgopen', `wid-edit', +;; `wid-edit+'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Bookmark+: extensions to standard library `bookmark.el'. +;; +;; The Bookmark+ libraries are these: +;; +;; `bookmark+.el' - main (driver) library (this file) +;; `bookmark+-mac.el' - Lisp macros +;; `bookmark+-lit.el' - (optional) code for highlighting bookmarks +;; `bookmark+-bmu.el' - code for the `*Bookmark List*' (bmenu) +;; `bookmark+-1.el' - other required code (non-bmenu) +;; `bookmark+-key.el' - key and menu bindings +;; +;; `bookmark+-doc.el' - documentation (comment-only file) +;; `bookmark+-chg.el' - change log (comment-only file) +;; +;; The documentation (in `bookmark+-doc.el') includes how to +;; byte-compile and install Bookmark+. The documentation is also +;; available in these ways: +;; +;; 1. From the bookmark list (`C-x r l'): +;; Use `?' to show the current bookmark-list status and general +;; help, then click link `Doc in Commentary' or link `Doc on the +;; Web'. +;; +;; 2. From the Emacs-Wiki Web site: +;; https://www.emacswiki.org/emacs/BookmarkPlus. +;; +;; 3. From the Bookmark+ group customization buffer: +;; `M-x customize-group bookmark-plus', then click link +;; `Commentary'. +;; +;; (The commentary links in #1 and #3 work only if you have library +;; `bookmark+-doc.el' in your `load-path'.) +;; +;; To report Bookmark+ bugs: `M-x customize-group bookmark-plus' +;; and then follow (e.g. click) the link `Send Bug Report', which +;; helps you prepare an email to me. +;; +;; +;; ****** NOTE ****** +;; +;; Whenever you update Bookmark+ (i.e., download new versions of +;; Bookmark+ source files), I recommend that you do the +;; following: +;; +;; 1. Delete all existing byte-compiled Bookmark+ files +;; (bookmark+*.elc). +;; 2. Load Bookmark+ (`load-library' or `require'). +;; 3. Byte-compile the source files. +;; +;; In particular, always load `bookmark+-mac.el' (not +;; `bookmark+-mac.elc') before you byte-compile new versions of +;; the files, in case there have been any changes to Lisp macros +;; (in `bookmark+-mac.el'). +;; +;; ****************** +;; +;; +;; ****** NOTE ****** +;; +;; On 2010-06-18, I changed the prefix used by package Bookmark+ +;; from `bookmarkp-' to `bmkp-'. THIS IS AN INCOMPATIBLE CHANGE. +;; I apologize for the inconvenience, but the new prefix is +;; preferable for a number of reasons, including easier +;; distinction from standard `bookmark.el' names. +;; +;; This change means that YOU MUST MANUALLY REPLACE ALL +;; OCCURRENCES of `bookmarkp-' by `bmkp-' in the following +;; places, if you used Bookmark+ prior to this change: +;; +;; 1. In your init file (`~/.emacs') or your `custom-file', if +;; you have one. This is needed if you customized any +;; Bookmark+ features. +;; +;; 2. In your default bookmark file, `bookmark-default-file' +;; (`~/.emacs.bmk'), and in any other bookmark files you might +;; have. +;; +;; 3. In your `*Bookmark List*' state file, +;; `bmkp-bmenu-state-file' (`~/.emacs-bmk-bmenu-state.el'). +;; +;; 4. In your `*Bookmark List*' commands file, +;; `bmkp-bmenu-commands-file' (`~/.emacs-bmk-bmenu-commands.el'), +;; if you have one. +;; +;; You can do this editing in a virgin Emacs session (`emacs +;; -Q'), that is, without loading Bookmark+. +;; +;; Alternatively, you can do this editing in an Emacs session +;; where Bookmark+ has been loaded, but in that case you must +;; TURN OFF AUTOMATIC SAVING of both your default bookmark file +;; and your `*Bookmark List*' state file. Otherwise, when you +;; quit Emacs your manually edits will be overwritten. +;; +;; To turn off this automatic saving, you can use `M-~' and `M-l' +;; in buffer `*Bookmark List*' (commands +;; `bmkp-toggle-saving-bookmark-file' and +;; `bmkp-toggle-saving-menu-list-state' - they are also in the +;; `Bookmark+' menu). +;; +;; +;; Again, sorry for this inconvenience. +;; +;; ****************** +;; +;; +;; Commands defined here: +;; +;; `bmkp-version'. +;; +;; Internal variables defined here: +;; +;; `bmkp-version-number'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;; + +(require 'bookmark) ; Vanilla Emacs. + +;;;###autoload (autoload 'bmkp-version-number "bookmark+") +(defconst bmkp-version-number "2018.10.17") + +;;;###autoload (autoload 'bmkp-version "bookmark+") +(defun bmkp-version () + "Show version number of library `bookmark+.el'." + (interactive) + (message "Bookmark+, version %s" bmkp-version-number)) + +;; This was made automatically buffer-local for vanilla Emacs 28. Do it here, for all Bookmark+ files. +(defvar bookmark-annotation-name nil + "Name of bookmark under edit in `bookmark-edit-annotation-mode'.") +(make-variable-buffer-local 'bookmark-annotation-name) + +;;;###autoload (autoload 'bookmark-bmenu-buffer "bookmark+") +;; This was added for vanilla Emacs 28. Add it here for older releases. +(defconst bookmark-bmenu-buffer "*Bookmark List*" + "Name of buffer used by vanilla Emacs for the bookmark-list display.") + +;;;###autoload (autoload 'bookmark-plus "bookmark+") +(defgroup bookmark-plus nil + "Bookmark enhancements." + :prefix "bmkp-" :group 'bookmark + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ +Bookmark+ bug: \ +&body=Describe bug here, starting with `emacs -Q'. \ +Don't forget to mention your Emacs and library versions.")) + :link '(url-link :tag "Download" "https://www.emacswiki.org/emacs/download/bookmark%2b.el") + :link '(url-link :tag "Description" "https://www.emacswiki.org/emacs/BookmarkPlus") + :link '(emacs-commentary-link :tag "Commentary" "bookmark+")) + +;; NOTE: +;; $$$$$$ Currently all vanilla Emacs functions that use constant `bookmark-bmenu-buffer' are +;; already redefined for Bookmark+. But if vanilla Emacs adds more such functions, and if those +;; functions could be invoked somehow when using Bookmark+, and if `bmkp-bmenu-buffer' has a +;; different value from `bookmark-bmenu-buffer', then some adjustment of Bookmark+ code will be +;; needed, to make sure the `bmkp-bmenu-buffer' value gets used instead. +;; +;;;###autoload (autoload 'bmkp-bmenu-buffer "bookmark+") +(defcustom bmkp-bmenu-buffer bookmark-bmenu-buffer + "Name of buffer used by Bookmark+ for the bookmark-list display. +The default value is that of vanilla Emacs constant `bookmark-bmenu-buffer'." + :type 'string :group 'bookmark-plus) + + + +;; Load Bookmark+ libraries. +;; +(eval-when-compile + (or (condition-case nil + (load-library "bookmark+-mac") ; Lisp macros. + (error nil)) ; Use load-library to ensure latest .elc. + (require 'bookmark+-mac))) ; Require, so can load separately if not on `load-path'. + +(require 'bookmark+-lit nil t) ; Optional (soft require) - no error if not found. If you do + ; not want to use `bookmark+-lit.el' then simply do not put + ; that file in your `load-path'. +(require 'bookmark+-bmu) ; `*Bookmark List*' (aka "menu list") stuff. +(require 'bookmark+-1) ; Rest of Bookmark+, except keys & menus. +(require 'bookmark+-key) ; Keys & menus. + +;;;;;;;;;;;;;;;;;;;;;;; + +(provide 'bookmark+) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; bookmark+.el ends here