summaryrefslogtreecommitdiff
path: root/lisp/bookmark.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/bookmark.el')
-rw-r--r--lisp/bookmark.el238
1 files changed, 146 insertions, 92 deletions
diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index cc9956c80a9..c604395dd7d 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -214,31 +214,28 @@ A non-nil value may result in truncated bookmark names."
;;;###autoload (define-key ctl-x-r-map "l" 'bookmark-bmenu-list)
;;;###autoload
-(defvar bookmark-map
- (let ((map (make-sparse-keymap)))
- ;; Read the help on all of these functions for details...
- (define-key map "x" 'bookmark-set)
- (define-key map "m" 'bookmark-set) ;"m"ark
- (define-key map "M" 'bookmark-set-no-overwrite) ;"M"aybe mark
- (define-key map "j" 'bookmark-jump)
- (define-key map "g" 'bookmark-jump) ;"g"o
- (define-key map "o" 'bookmark-jump-other-window)
- (define-key map "5" 'bookmark-jump-other-frame)
- (define-key map "i" 'bookmark-insert)
- (define-key map "e" 'edit-bookmarks)
- (define-key map "f" 'bookmark-insert-location) ;"f"ind
- (define-key map "r" 'bookmark-rename)
- (define-key map "d" 'bookmark-delete)
- (define-key map "D" 'bookmark-delete-all)
- (define-key map "l" 'bookmark-load)
- (define-key map "w" 'bookmark-write)
- (define-key map "s" 'bookmark-save)
- map)
- "Keymap containing bindings to bookmark functions.
+(defvar-keymap bookmark-map
+ :doc "Keymap containing bindings to bookmark functions.
It is not bound to any key by default: to bind it
so that you have a bookmark prefix, just use `global-set-key' and bind a
key of your choice to variable `bookmark-map'. All interactive bookmark
-functions have a binding in this keymap.")
+functions have a binding in this keymap."
+ "x" #'bookmark-set
+ "m" #'bookmark-set ;"m"ark
+ "M" #'bookmark-set-no-overwrite ;"M"aybe mark
+ "j" #'bookmark-jump
+ "g" #'bookmark-jump ;"g"o
+ "o" #'bookmark-jump-other-window
+ "5" #'bookmark-jump-other-frame
+ "i" #'bookmark-insert
+ "e" #'edit-bookmarks
+ "f" #'bookmark-insert-location ;"f"ind
+ "r" #'bookmark-rename
+ "d" #'bookmark-delete
+ "D" #'bookmark-delete-all
+ "l" #'bookmark-load
+ "w" #'bookmark-write
+ "s" #'bookmark-save)
;;;###autoload (fset 'bookmark-map bookmark-map)
@@ -349,6 +346,17 @@ This point is in `bookmark-current-buffer'.")
BOOKMARK-RECORD is, e.g., one element from `bookmark-alist'."
(car bookmark-record))
+(defun bookmark-type-from-full-record (bookmark-record)
+ "Return then type of BOOKMARK-RECORD.
+BOOKMARK-RECORD is, e.g., one element from `bookmark-alist'. It's
+type is read from the symbol property named
+`bookmark-handler-type' read on the record handler function."
+ (let ((handler (bookmark-get-handler bookmark-record)))
+ (when (autoloadp (symbol-function handler))
+ (autoload-do-load (symbol-function handler)))
+ (if (symbolp handler)
+ (get handler 'bookmark-handler-type)
+ "")))
(defun bookmark-all-names ()
"Return a list of all current bookmark names."
@@ -503,11 +511,8 @@ If DEFAULT is nil then return empty string for empty input."
'string-lessp)
(bookmark-all-names)))
(let* ((completion-ignore-case bookmark-completion-ignore-case)
- (default (unless (equal "" default) default))
- (prompt (concat prompt (if default
- (format " (%s): " default)
- ": "))))
- (completing-read prompt
+ (default (unless (equal "" default) default)))
+ (completing-read (format-prompt prompt default)
(lambda (string pred action)
(if (eq action 'metadata)
'(metadata (category . bookmark))
@@ -518,8 +523,9 @@ If DEFAULT is nil then return empty string for empty input."
(defmacro bookmark-maybe-historicize-string (string)
"Put STRING into the bookmark prompt history, if caller non-interactive.
-We need this because sometimes bookmark functions are invoked from
-menus, so `completing-read' never gets a chance to set `bookmark-history'."
+We need this because sometimes bookmark functions are invoked
+from other commands that pass in the bookmark name, so
+`completing-read' never gets a chance to set `bookmark-history'."
`(or
(called-interactively-p 'interactive)
(setq bookmark-history (cons ,string bookmark-history))))
@@ -818,11 +824,9 @@ CODING is the symbol of the coding-system in which the file is encoded."
(define-obsolete-function-alias 'bookmark-maybe-message 'message "27.1")
-(defvar bookmark-minibuffer-read-name-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map minibuffer-local-map)
- (define-key map "\C-w" 'bookmark-yank-word)
- map))
+(defvar-keymap bookmark-minibuffer-read-name-map
+ :parent minibuffer-local-map
+ "C-w" #'bookmark-yank-word)
(defun bookmark-set-internal (prompt name overwrite-or-push)
"Set a bookmark using specified NAME or prompting with PROMPT.
@@ -926,7 +930,7 @@ it removes only the first instance of a bookmark with that name from
the list of bookmarks.)"
(interactive (list nil current-prefix-arg))
(let ((prompt
- (if no-overwrite "Set bookmark" "Set bookmark unconditionally")))
+ (if no-overwrite "Append bookmark named" "Set bookmark named")))
(bookmark-set-internal prompt name (if no-overwrite 'push 'overwrite))))
;;;###autoload
@@ -997,12 +1001,10 @@ annotations."
"Function to return default text to use for a bookmark annotation.
It takes one argument, the name of the bookmark, as a string.")
-(defvar bookmark-edit-annotation-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map text-mode-map)
- (define-key map "\C-c\C-c" 'bookmark-send-edited-annotation)
- map)
- "Keymap for editing an annotation of a bookmark.")
+(defvar-keymap bookmark-edit-annotation-mode-map
+ :doc "Keymap for editing an annotation of a bookmark."
+ :parent text-mode-map
+ "C-c C-c" #'bookmark-send-edited-annotation)
(defun bookmark-insert-annotation (bookmark-name-or-record)
"Insert annotation for BOOKMARK-NAME-OR-RECORD at point."
@@ -1287,7 +1289,10 @@ then offer interactively to relocate BOOKMARK-NAME-OR-RECORD."
(defun bookmark-default-handler (bmk-record)
"Default handler to jump to a particular bookmark location.
BMK-RECORD is a bookmark record, not a bookmark name (i.e., not a string).
-Changes current buffer and point and returns nil, or signals a `file-error'."
+Changes current buffer and point and returns nil, or signals a `file-error'.
+
+If BMK-RECORD has a property called `buffer', it should be a live
+buffer object, and this buffer will be selected."
(let ((file (bookmark-get-filename bmk-record))
(buf (bookmark-prop-get bmk-record 'buffer))
(forward-str (bookmark-get-front-context-string bmk-record))
@@ -1361,7 +1366,6 @@ minibuffer history list `bookmark-history'."
(bookmark-get-filename bookmark-name-or-record)
"-- Unknown location --"))
-
;;;###autoload
(defun bookmark-rename (old-name &optional new-name)
"Change the name of OLD-NAME bookmark to NEW-NAME name.
@@ -1707,44 +1711,43 @@ unique numeric suffixes \"<2>\", \"<3>\", etc."
(defvar bookmark-bmenu-hidden-bookmarks ())
-
-(defvar bookmark-bmenu-mode-map
- (let ((map (make-keymap)))
- (set-keymap-parent map tabulated-list-mode-map)
- (define-key map "v" 'bookmark-bmenu-select)
- (define-key map "w" 'bookmark-bmenu-locate)
- (define-key map "5" 'bookmark-bmenu-other-frame)
- (define-key map "2" 'bookmark-bmenu-2-window)
- (define-key map "1" 'bookmark-bmenu-1-window)
- (define-key map "j" 'bookmark-bmenu-this-window)
- (define-key map "\C-c\C-c" 'bookmark-bmenu-this-window)
- (define-key map "f" 'bookmark-bmenu-this-window)
- (define-key map "\C-m" 'bookmark-bmenu-this-window)
- (define-key map "o" 'bookmark-bmenu-other-window)
- (define-key map "\C-o" 'bookmark-bmenu-switch-other-window)
- (define-key map "s" 'bookmark-bmenu-save)
- (define-key map "\C-x\C-s" 'bookmark-bmenu-save)
- (define-key map "k" 'bookmark-bmenu-delete)
- (define-key map "\C-d" 'bookmark-bmenu-delete-backwards)
- (define-key map "x" 'bookmark-bmenu-execute-deletions)
- (define-key map "d" 'bookmark-bmenu-delete)
- (define-key map "D" 'bookmark-bmenu-delete-all)
- (define-key map " " 'next-line)
- (define-key map "\177" 'bookmark-bmenu-backup-unmark)
- (define-key map "u" 'bookmark-bmenu-unmark)
- (define-key map "U" 'bookmark-bmenu-unmark-all)
- (define-key map "m" 'bookmark-bmenu-mark)
- (define-key map "M" 'bookmark-bmenu-mark-all)
- (define-key map "l" 'bookmark-bmenu-load)
- (define-key map "r" 'bookmark-bmenu-rename)
- (define-key map "R" 'bookmark-bmenu-relocate)
- (define-key map "t" 'bookmark-bmenu-toggle-filenames)
- (define-key map "a" 'bookmark-bmenu-show-annotation)
- (define-key map "A" 'bookmark-bmenu-show-all-annotations)
- (define-key map "e" 'bookmark-bmenu-edit-annotation)
- (define-key map "/" 'bookmark-bmenu-search)
- (define-key map [mouse-2] 'bookmark-bmenu-other-window-with-mouse)
- map))
+(defvar-keymap bookmark-bmenu-mode-map
+ :doc "Keymap for `bookmark-bmenu-mode'."
+ :parent tabulated-list-mode-map
+ "v" #'bookmark-bmenu-select
+ "w" #'bookmark-bmenu-locate
+ "5" #'bookmark-bmenu-other-frame
+ "2" #'bookmark-bmenu-2-window
+ "1" #'bookmark-bmenu-1-window
+ "j" #'bookmark-bmenu-this-window
+ "C-c C-c" #'bookmark-bmenu-this-window
+ "f" #'bookmark-bmenu-this-window
+ "C-m" #'bookmark-bmenu-this-window
+ "o" #'bookmark-bmenu-other-window
+ "C-o" #'bookmark-bmenu-switch-other-window
+ "s" #'bookmark-bmenu-save
+ "C-x C-s" #'bookmark-bmenu-save
+ "k" #'bookmark-bmenu-delete
+ "C-d" #'bookmark-bmenu-delete-backwards
+ "x" #'bookmark-bmenu-execute-deletions
+ "d" #'bookmark-bmenu-delete
+ "D" #'bookmark-bmenu-delete-all
+ "S-SPC" #'previous-line
+ "SPC" #'next-line
+ "DEL" #'bookmark-bmenu-backup-unmark
+ "u" #'bookmark-bmenu-unmark
+ "U" #'bookmark-bmenu-unmark-all
+ "m" #'bookmark-bmenu-mark
+ "M" #'bookmark-bmenu-mark-all
+ "l" #'bookmark-bmenu-load
+ "r" #'bookmark-bmenu-rename
+ "R" #'bookmark-bmenu-relocate
+ "t" #'bookmark-bmenu-toggle-filenames
+ "a" #'bookmark-bmenu-show-annotation
+ "A" #'bookmark-bmenu-show-all-annotations
+ "e" #'bookmark-bmenu-edit-annotation
+ "/" #'bookmark-bmenu-search
+ "<mouse-2>" #'bookmark-bmenu-other-window-with-mouse)
(easy-menu-define bookmark-menu bookmark-bmenu-mode-map
"Menu for `bookmark-bmenu'."
@@ -1802,6 +1805,7 @@ Don't affect the buffer ring order."
(let (entries)
(dolist (full-record (bookmark-maybe-sort-alist))
(let* ((name (bookmark-name-from-full-record full-record))
+ (type (bookmark-type-from-full-record full-record))
(annotation (bookmark-get-annotation full-record))
(location (bookmark-location full-record)))
(push (list
@@ -1815,11 +1819,38 @@ Don't affect the buffer ring order."
'follow-link t
'help-echo "mouse-2: go to this bookmark in other window")
name)
+ ,(or type "")
,@(if bookmark-bmenu-toggle-filenames
(list location))])
entries)))
- (tabulated-list-init-header)
- (setq tabulated-list-entries entries))
+ ;; The value of `bookmark-sort-flag' might have changed since the
+ ;; last time the buffer contents were generated, so re-check it.
+ (if bookmark-sort-flag
+ (progn
+ (setq tabulated-list-sort-key '("Bookmark Name" . nil))
+ (setq tabulated-list-entries entries))
+ (setq tabulated-list-sort-key nil)
+ ;; And since we're not sorting by bookmark name, show bookmarks
+ ;; according to order of creation, with the most recently
+ ;; created bookmarks at the top and the least recently created
+ ;; at the bottom.
+ ;;
+ ;; Note that clicking the column sort toggle for the bookmark
+ ;; name column will invoke the `tabulated-list-mode' sort, which
+ ;; uses `bookmark-bmenu--name-predicate' to sort lexically by
+ ;; bookmark name instead of by (reverse) creation order.
+ ;; Clicking the toggle again will reverse the lexical sort, but
+ ;; the sort will still be lexical not creation-order. However,
+ ;; if the user reverts the buffer, then the above check of
+ ;; `bookmark-sort-flag' will happen again and the buffer will
+ ;; go back to a creation-order sort. This is all expected
+ ;; behavior, as documented in `bookmark-bmenu-mode'.
+ (setq tabulated-list-entries (reverse entries)))
+ ;; Generate the header only after `tabulated-list-sort-key' is
+ ;; settled, because if that's non-nil then the sort-direction
+ ;; indicator will be shown in the named column, but if it's
+ ;; nil then the indicator will not be shown.
+ (tabulated-list-init-header))
(tabulated-list-print t))
;;;###autoload
@@ -1863,6 +1894,18 @@ deletion, or > if it is flagged for displaying."
Each line describes one of the bookmarks in Emacs.
Letters do not insert themselves; instead, they are commands.
Bookmark names preceded by a \"*\" have annotations.
+
+If `bookmark-sort-flag' is non-nil, then sort the list by
+bookmark name (case-insensitively, in collation order); the
+direction of that sort can be reversed by using the column sort
+toggle for the bookmark name column.
+
+If `bookmark-sort-flag' is nil, then sort the list by bookmark
+creation order, with most recently created bookmarks on top.
+However, the column sort toggle will still activate (and
+thereafter toggle the direction of) lexical sorting by bookmark name.
+At any time you may use \\[revert-buffer] to go back to sorting by creation order.
+
\\<bookmark-bmenu-mode-map>
\\[bookmark-bmenu-mark] -- mark bookmark to be displayed.
\\[bookmark-bmenu-mark-all] -- mark all listed bookmarks to be displayed.
@@ -1895,18 +1938,23 @@ Bookmark names preceded by a \"*\" have annotations.
in another buffer.
\\[bookmark-bmenu-show-all-annotations] -- show the annotations of all bookmarks in another buffer.
\\[bookmark-bmenu-edit-annotation] -- edit the annotation for the current bookmark.
-\\[bookmark-bmenu-search] -- incrementally search for bookmarks."
+\\[bookmark-bmenu-search] -- incrementally search for bookmarks.
+\\[revert-buffer] -- refresh the buffer, and thus refresh the sort order (useful
+ if `bookmark-sort-flag' is nil)."
(setq truncate-lines t)
(setq buffer-read-only t)
;; FIXME: The header could also display the current default bookmark file
;; according to `bookmark-bookmarks-timestamp'.
(setq tabulated-list-format
`[("" 1) ;; Space to add "*" for bookmark with annotation
- ("Bookmark" ,bookmark-bmenu-file-column bookmark-bmenu--name-predicate)
+ ("Bookmark Name"
+ ,bookmark-bmenu-file-column bookmark-bmenu--name-predicate)
+ ("Type" 8 bookmark-bmenu--type-predicate)
,@(if bookmark-bmenu-toggle-filenames
'(("File" 0 bookmark-bmenu--file-predicate)))])
(setq tabulated-list-padding bookmark-bmenu-marks-width)
- (setq tabulated-list-sort-key '("Bookmark" . nil))
+ (when bookmark-sort-flag
+ (setq tabulated-list-sort-key '("Bookmark Name" . nil)))
(add-hook 'tabulated-list-revert-hook #'bookmark-bmenu--revert nil t)'
(setq revert-buffer-function 'bookmark-bmenu--revert)
(tabulated-list-init-header))
@@ -1915,13 +1963,19 @@ Bookmark names preceded by a \"*\" have annotations.
(defun bookmark-bmenu--name-predicate (a b)
"Predicate to sort \"*Bookmark List*\" buffer by the name column.
This is used for `tabulated-list-format' in `bookmark-bmenu-mode'."
- (string< (caar a) (caar b)))
+ (string-collate-lessp (caar a) (caar b) nil t))
+(defun bookmark-bmenu--type-predicate (a b)
+ "Predicate to sort \"*Bookmark List*\" buffer by the type column.
+This is used for `tabulated-list-format' in `bookmark-bmenu-mode'."
+ (string-collate-lessp (elt (cadr a) 2) (elt (cadr b) 2) nil t))
(defun bookmark-bmenu--file-predicate (a b)
"Predicate to sort \"*Bookmark List*\" buffer by the file column.
This is used for `tabulated-list-format' in `bookmark-bmenu-mode'."
- (string< (bookmark-location (car a)) (bookmark-location (car b))))
+ (string-collate-lessp (bookmark-location (car a))
+ (bookmark-location (car b))
+ nil t))
(defun bookmark-bmenu-toggle-filenames (&optional show)
@@ -2324,10 +2378,10 @@ Prompt with completion for the new path."
(lambda ()
(setq timer (run-with-idle-timer
bookmark-search-delay 'repeat
- #'(lambda (buf)
- (with-current-buffer buf
- (bookmark-bmenu-filter-alist-by-regexp
- (minibuffer-contents))))
+ (lambda (buf)
+ (with-current-buffer buf
+ (bookmark-bmenu-filter-alist-by-regexp
+ (minibuffer-contents))))
(current-buffer))))
(read-string "Pattern: ")
(when timer (cancel-timer timer) (setq timer nil)))