aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Giraud2022-05-31 20:35:39 +0200
committerLars Ingebrigtsen2022-05-31 20:35:39 +0200
commitf461eb8fa770a6f6b048f13684bd697756f8790c (patch)
tree7ba450580e1781c14be8b1fc032090fa5e304432
parent6a2cc870d23485a8f440a8b58768eefdf16c8912 (diff)
downloademacs-f461eb8fa770a6f6b048f13684bd697756f8790c.tar.gz
emacs-f461eb8fa770a6f6b048f13684bd697756f8790c.zip
Add a last-modified field when a bookmark is set
* test/lisp/bookmark-tests.el (bookmark-tests-make-record) (bookmark-tests-make-record-list, bookmark-tests-set): fix tests to not consider last-modified in bookmark equality. * lisp/bookmark.el (bookmark-make-record-default): add a last-modified field. (bookmark-sort-flag): add the 'last-modified choice. (bookmark-get-last-modified): new function to get last-modified bookmark field. (bookmark-maybe-sort-alist): sort in last-modified first order. (bookmark-completing-read): use `bookmark-maybe-sort-alist'.
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/bookmark.el99
-rw-r--r--test/lisp/bookmark-tests.el30
3 files changed, 85 insertions, 49 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 0d4532985b2..597f92cfce3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1690,6 +1690,11 @@ manual for more details.
1690Types are registered via a 'bookmark-handler-type' symbol property on 1690Types are registered via a 'bookmark-handler-type' symbol property on
1691the jumping function. 1691the jumping function.
1692 1692
1693+++
1694*** 'bookmark-sort-flag' can now be set to 'last-modified'.
1695This will display bookmark list from most recently set to least
1696recently set.
1697
1693--- 1698---
1694*** New minor mode 'elide-head-mode'. 1699*** New minor mode 'elide-head-mode'.
1695Enabling this minor mode turns on hiding header material, like 1700Enabling this minor mode turns on hiding header material, like
diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index c604395dd7d..8e251e9de87 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -115,10 +115,18 @@ just use the value of `version-control'."
115 115
116 116
117(defcustom bookmark-sort-flag t 117(defcustom bookmark-sort-flag t
118 "Non-nil means that bookmarks will be displayed sorted by bookmark name. 118 "This controls the bookmark display sorting.
119Otherwise they will be displayed in LIFO order (that is, most 119nil means they will be displayed in LIFO order (that is, most
120recently set ones come first, oldest ones come last)." 120recently created ones come first, oldest ones come last).
121 :type 'boolean) 121
122`last-modified' means that bookmarks will be displayed sorted
123from most recently set to last recently set.
124
125Other values means that bookmarks will be displayed sorted by
126bookmark name."
127 :type '(choice (const :tag "By name" t)
128 (const :tag "By modified time" last-modified)
129 (const :tag "By creation time" nil)))
122 130
123 131
124(defcustom bookmark-menu-confirm-deletion nil 132(defcustom bookmark-menu-confirm-deletion nil
@@ -460,6 +468,10 @@ In other words, return all information but the name."
460 "Return the handler function for BOOKMARK-NAME-OR-RECORD, or nil if none." 468 "Return the handler function for BOOKMARK-NAME-OR-RECORD, or nil if none."
461 (bookmark-prop-get bookmark-name-or-record 'handler)) 469 (bookmark-prop-get bookmark-name-or-record 'handler))
462 470
471(defun bookmark-get-last-modified (bookmark-name-or-record)
472 "Return the last-modified for BOOKMARK-NAME-OR-RECORD, or nil if none."
473 (bookmark-prop-get bookmark-name-or-record 'last-modified))
474
463(defvar bookmark-history nil 475(defvar bookmark-history nil
464 "The history list for bookmark functions.") 476 "The history list for bookmark functions.")
465 477
@@ -497,6 +509,21 @@ See user option `bookmark-set-fringe'."
497 (when (eq 'bookmark (overlay-get temp 'category)) 509 (when (eq 'bookmark (overlay-get temp 'category))
498 (delete-overlay (setq found temp)))))))))) 510 (delete-overlay (setq found temp))))))))))
499 511
512(defun bookmark-maybe-sort-alist ()
513 "Return `bookmark-alist' for display.
514If `bookmark-sort-flag' is T, then return a sorted by name copy of the alist.
515If `bookmark-sort-flag' is LAST-MODIFIED, then return a sorted by last modified
516copy of the alist. Otherwise, just return `bookmark-alist', which by default
517is ordered from most recently created to least recently created bookmark."
518 (let ((copy (copy-alist bookmark-alist)))
519 (cond ((eq bookmark-sort-flag t)
520 (sort copy (lambda (x y) (string-lessp (car x) (car y)))))
521 ((eq bookmark-sort-flag 'last-modified)
522 (sort copy (lambda (x y)
523 (time-less-p (bookmark-get-last-modified y)
524 (bookmark-get-last-modified x)))))
525 (t copy))))
526
500(defun bookmark-completing-read (prompt &optional default) 527(defun bookmark-completing-read (prompt &optional default)
501 "Prompting with PROMPT, read a bookmark name in completion. 528 "Prompting with PROMPT, read a bookmark name in completion.
502PROMPT will get a \": \" stuck on the end no matter what, so you 529PROMPT will get a \": \" stuck on the end no matter what, so you
@@ -506,10 +533,8 @@ If DEFAULT is nil then return empty string for empty input."
506 (bookmark-maybe-load-default-file) ; paranoia 533 (bookmark-maybe-load-default-file) ; paranoia
507 (if (listp last-nonmenu-event) 534 (if (listp last-nonmenu-event)
508 (bookmark-menu-popup-paned-menu t prompt 535 (bookmark-menu-popup-paned-menu t prompt
509 (if bookmark-sort-flag 536 (mapcar 'bookmark-name-from-full-record
510 (sort (bookmark-all-names) 537 (bookmark-maybe-sort-alist)))
511 'string-lessp)
512 (bookmark-all-names)))
513 (let* ((completion-ignore-case bookmark-completion-ignore-case) 538 (let* ((completion-ignore-case bookmark-completion-ignore-case)
514 (default (unless (equal "" default) default))) 539 (default (unless (equal "" default) default)))
515 (completing-read (format-prompt prompt default) 540 (completing-read (format-prompt prompt default)
@@ -630,7 +655,8 @@ If POSN is non-nil, record POSN as the point instead of `(point)'."
630 (point) 655 (point)
631 (- (point) bookmark-search-size)) 656 (- (point) bookmark-search-size))
632 nil)))) 657 nil))))
633 (position . ,(or posn (point))))) 658 (position . ,(or posn (point)))
659 (last-modified . ,(current-time))))
634 660
635 661
636;;; File format stuff 662;;; File format stuff
@@ -1140,15 +1166,6 @@ it to the name of the bookmark currently being set, advancing
1140 (car bookmark-bookmarks-timestamp))))))) 1166 (car bookmark-bookmarks-timestamp)))))))
1141 (bookmark-load (car bookmark-bookmarks-timestamp) t t)))) 1167 (bookmark-load (car bookmark-bookmarks-timestamp) t t))))
1142 1168
1143(defun bookmark-maybe-sort-alist ()
1144 "Return `bookmark-alist' for display.
1145If `bookmark-sort-flag' is non-nil, then return a sorted copy of the alist.
1146Otherwise, just return `bookmark-alist', which by default is ordered
1147from most recently created to least recently created bookmark."
1148 (if bookmark-sort-flag
1149 (sort (copy-alist bookmark-alist)
1150 (lambda (x y) (string-lessp (car x) (car y))))
1151 bookmark-alist))
1152 1169
1153 1170
1154(defvar bookmark-after-jump-hook nil 1171(defvar bookmark-after-jump-hook nil
@@ -1825,27 +1842,28 @@ Don't affect the buffer ring order."
1825 entries))) 1842 entries)))
1826 ;; The value of `bookmark-sort-flag' might have changed since the 1843 ;; The value of `bookmark-sort-flag' might have changed since the
1827 ;; last time the buffer contents were generated, so re-check it. 1844 ;; last time the buffer contents were generated, so re-check it.
1828 (if bookmark-sort-flag 1845 (cond ((eq bookmark-sort-flag t)
1829 (progn 1846 (setq tabulated-list-sort-key '("Bookmark Name" . nil)
1830 (setq tabulated-list-sort-key '("Bookmark Name" . nil)) 1847 tabulated-list-entries entries))
1831 (setq tabulated-list-entries entries)) 1848 ((or (null bookmark-sort-flag)
1832 (setq tabulated-list-sort-key nil) 1849 (eq bookmark-sort-flag 'last-modified))
1833 ;; And since we're not sorting by bookmark name, show bookmarks 1850 (setq tabulated-list-sort-key nil)
1834 ;; according to order of creation, with the most recently 1851 ;; And since we're not sorting by bookmark name, show bookmarks
1835 ;; created bookmarks at the top and the least recently created 1852 ;; according to order of creation, with the most recently
1836 ;; at the bottom. 1853 ;; created bookmarks at the top and the least recently created
1837 ;; 1854 ;; at the bottom.
1838 ;; Note that clicking the column sort toggle for the bookmark 1855 ;;
1839 ;; name column will invoke the `tabulated-list-mode' sort, which 1856 ;; Note that clicking the column sort toggle for the bookmark
1840 ;; uses `bookmark-bmenu--name-predicate' to sort lexically by 1857 ;; name column will invoke the `tabulated-list-mode' sort, which
1841 ;; bookmark name instead of by (reverse) creation order. 1858 ;; uses `bookmark-bmenu--name-predicate' to sort lexically by
1842 ;; Clicking the toggle again will reverse the lexical sort, but 1859 ;; bookmark name instead of by (reverse) creation order.
1843 ;; the sort will still be lexical not creation-order. However, 1860 ;; Clicking the toggle again will reverse the lexical sort, but
1844 ;; if the user reverts the buffer, then the above check of 1861 ;; the sort will still be lexical not creation-order. However,
1845 ;; `bookmark-sort-flag' will happen again and the buffer will 1862 ;; if the user reverts the buffer, then the above check of
1846 ;; go back to a creation-order sort. This is all expected 1863 ;; `bookmark-sort-flag' will happen again and the buffer will
1847 ;; behavior, as documented in `bookmark-bmenu-mode'. 1864 ;; go back to a creation-order sort. This is all expected
1848 (setq tabulated-list-entries (reverse entries))) 1865 ;; behavior, as documented in `bookmark-bmenu-mode'.
1866 (setq tabulated-list-entries (reverse entries))))
1849 ;; Generate the header only after `tabulated-list-sort-key' is 1867 ;; Generate the header only after `tabulated-list-sort-key' is
1850 ;; settled, because if that's non-nil then the sort-direction 1868 ;; settled, because if that's non-nil then the sort-direction
1851 ;; indicator will be shown in the named column, but if it's 1869 ;; indicator will be shown in the named column, but if it's
@@ -1953,7 +1971,8 @@ At any time you may use \\[revert-buffer] to go back to sorting by creation orde
1953 ,@(if bookmark-bmenu-toggle-filenames 1971 ,@(if bookmark-bmenu-toggle-filenames
1954 '(("File" 0 bookmark-bmenu--file-predicate)))]) 1972 '(("File" 0 bookmark-bmenu--file-predicate)))])
1955 (setq tabulated-list-padding bookmark-bmenu-marks-width) 1973 (setq tabulated-list-padding bookmark-bmenu-marks-width)
1956 (when bookmark-sort-flag 1974 (when (and bookmark-sort-flag
1975 (not (eq bookmark-sort-flag 'last-modified)))
1957 (setq tabulated-list-sort-key '("Bookmark Name" . nil))) 1976 (setq tabulated-list-sort-key '("Bookmark Name" . nil)))
1958 (add-hook 'tabulated-list-revert-hook #'bookmark-bmenu--revert nil t)' 1977 (add-hook 'tabulated-list-revert-hook #'bookmark-bmenu--revert nil t)'
1959 (setq revert-buffer-function 'bookmark-bmenu--revert) 1978 (setq revert-buffer-function 'bookmark-bmenu--revert)
diff --git a/test/lisp/bookmark-tests.el b/test/lisp/bookmark-tests.el
index ae7331fcc2b..a2d8f2d260b 100644
--- a/test/lisp/bookmark-tests.el
+++ b/test/lisp/bookmark-tests.el
@@ -197,6 +197,9 @@ the lexically-bound variable `buffer'."
197 (bookmark-maybe-historicize-string "foo") 197 (bookmark-maybe-historicize-string "foo")
198 (should (equal (car bookmark-history) "foo")))) 198 (should (equal (car bookmark-history) "foo"))))
199 199
200(defun bookmark-remove-last-modified (bmk)
201 (assoc-delete-all 'last-modified bmk))
202
200(ert-deftest bookmark-tests-make-record () 203(ert-deftest bookmark-tests-make-record ()
201 (with-bookmark-test-file 204 (with-bookmark-test-file
202 (let* ((record `("example.txt" (filename . ,bookmark-tests-example-file) 205 (let* ((record `("example.txt" (filename . ,bookmark-tests-example-file)
@@ -206,9 +209,11 @@ the lexically-bound variable `buffer'."
206 (defaults "example.txt")))) 209 (defaults "example.txt"))))
207 (with-current-buffer buffer 210 (with-current-buffer buffer
208 (goto-char 3) 211 (goto-char 3)
209 (should (equal (bookmark-make-record) record)) 212 (should (equal (bookmark-remove-last-modified (bookmark-make-record))
213 record))
210 ;; calling twice gives same record 214 ;; calling twice gives same record
211 (should (equal (bookmark-make-record) record)))))) 215 (should (equal (bookmark-remove-last-modified (bookmark-make-record))
216 record))))))
212 217
213(ert-deftest bookmark-tests-make-record-list () 218(ert-deftest bookmark-tests-make-record-list ()
214 (with-bookmark-test-file-list 219 (with-bookmark-test-file-list
@@ -219,9 +224,11 @@ the lexically-bound variable `buffer'."
219 (defaults "example.txt")))) 224 (defaults "example.txt"))))
220 (with-current-buffer buffer 225 (with-current-buffer buffer
221 (goto-char 3) 226 (goto-char 3)
222 (should (equal (bookmark-make-record) record)) 227 (should (equal (bookmark-remove-last-modified (bookmark-make-record))
228 record))
223 ;; calling twice gives same record 229 ;; calling twice gives same record
224 (should (equal (bookmark-make-record) record)))))) 230 (should (equal (bookmark-remove-last-modified (bookmark-make-record))
231 record))))))
225 232
226(ert-deftest bookmark-tests-make-record-function () 233(ert-deftest bookmark-tests-make-record-function ()
227 (with-bookmark-test 234 (with-bookmark-test
@@ -255,15 +262,18 @@ the lexically-bound variable `buffer'."
255 ;; Set first bookmark 262 ;; Set first bookmark
256 (goto-char (point-min)) 263 (goto-char (point-min))
257 (bookmark-set "foo") 264 (bookmark-set "foo")
258 (should (equal bookmark-alist (list bmk1))) 265 (should (equal (mapcar #'bookmark-remove-last-modified bookmark-alist)
266 (list bmk1)))
259 ;; Replace that bookmark 267 ;; Replace that bookmark
260 (goto-char (point-max)) 268 (goto-char (point-max))
261 (bookmark-set "foo") 269 (bookmark-set "foo")
262 (should (equal bookmark-alist (list bmk2))) 270 (should (equal (mapcar #'bookmark-remove-last-modified bookmark-alist)
271 (list bmk2)))
263 ;; Push another bookmark with the same name 272 ;; Push another bookmark with the same name
264 (goto-char (point-min)) 273 (goto-char (point-min))
265 (bookmark-set "foo" t) ; NO-OVERWRITE is t 274 (bookmark-set "foo" t) ; NO-OVERWRITE is t
266 (should (equal bookmark-alist (list bmk1 bmk2))) 275 (should (equal (mapcar #'bookmark-remove-last-modified bookmark-alist)
276 (list bmk1 bmk2)))
267 277
268 ;; 2. bookmark-set-no-overwrite 278 ;; 2. bookmark-set-no-overwrite
269 ;; Don't overwrite 279 ;; Don't overwrite
@@ -271,11 +281,13 @@ the lexically-bound variable `buffer'."
271 ;; Set new bookmark 281 ;; Set new bookmark
272 (setq bookmark-alist nil) 282 (setq bookmark-alist nil)
273 (bookmark-set-no-overwrite "foo") 283 (bookmark-set-no-overwrite "foo")
274 (should (equal bookmark-alist (list bmk1))) 284 (should (equal (mapcar #'bookmark-remove-last-modified bookmark-alist)
285 (list bmk1)))
275 ;; Push another bookmark with the same name 286 ;; Push another bookmark with the same name
276 (goto-char (point-max)) 287 (goto-char (point-max))
277 (bookmark-set-no-overwrite "foo" t) ; PUSH-BOOKMARK is t 288 (bookmark-set-no-overwrite "foo" t) ; PUSH-BOOKMARK is t
278 (should (equal bookmark-alist (list bmk2 bmk1))) 289 (should (equal (mapcar #'bookmark-remove-last-modified bookmark-alist)
290 (list bmk2 bmk1)))
279 291
280 ;; 3. bookmark-set-internal 292 ;; 3. bookmark-set-internal
281 (should-error (bookmark-set-internal "foo" "bar" t)))))) 293 (should-error (bookmark-set-internal "foo" "bar" t))))))