From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Matthew White Newsgroups: gmane.emacs.devel Subject: Re: Add new functions to mark/unmark/delete all bookmarks Date: Sat, 25 Jul 2020 12:46:18 +0200 Message-ID: <20200725124618.49a073b1@pineapple> References: <20200724005105.11f85d5f@pineapple> <87pn8ku3y9.fsf@red-bean.com> Mime-Version: 1.0 Content-Type: multipart/signed; boundary="Sig_/qhdSDt=oEbfDKGsOToy0VRb"; protocol="application/pgp-signature"; micalg=pgp-sha256 Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="2741"; mail-complaints-to="usenet@ciao.gmane.io" To: Karl Fogel , emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sat Jul 25 12:49:22 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jzHk0-0000a6-Pd for ged-emacs-devel@m.gmane-mx.org; Sat, 25 Jul 2020 12:49:21 +0200 Original-Received: from localhost ([::1]:49972 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jzHjz-00075R-MM for ged-emacs-devel@m.gmane-mx.org; Sat, 25 Jul 2020 06:49:19 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:41974) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jzHha-0006cF-7a for emacs-devel@gnu.org; Sat, 25 Jul 2020 06:46:50 -0400 Original-Received: from devianza.investici.org ([198.167.222.108]:43613) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jzHhV-00068x-0w for emacs-devel@gnu.org; Sat, 25 Jul 2020 06:46:49 -0400 Original-Received: from mx2.investici.org (unknown [127.0.0.1]) by devianza.investici.org (Postfix) with ESMTP id C991CE06E0; Sat, 25 Jul 2020 10:46:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inventati.org; s=stigmate; t=1595673989; bh=1NkWFL5wG65sKKhc2QeMQXyoHlkmRps/i9i8TAZurE4=; h=Date:From:To:Subject:In-Reply-To:References:From; b=LbVciKVVBGspkVyfGSAk6wF4MiTfMnF1O64uxevguLB2hSij1jFGQMQK8Jcl6w7S8 5WG28R05LRJiueh4h921rxjL4P/STpV+47RgySdNqJvq3ZCPchELlzXHw/eZVUlshJ mJesO0viOrCxDlOf1EPIxztV4Bc1/F4Aquvz6S04= Original-Received: from [198.167.222.108] (mx2.investici.org [198.167.222.108]) (Authenticated sender: mehw.is.me@inventati.org) by localhost (Postfix) with ESMTPSA id 7A21CE06BC; Sat, 25 Jul 2020 10:46:28 +0000 (UTC) In-Reply-To: <87pn8ku3y9.fsf@red-bean.com> X-Mailer: Claws Mail 3.17.5 (GTK+ 2.24.32; x86_64-pc-linux-gnu) Received-SPF: pass client-ip=198.167.222.108; envelope-from=mehw.is.me@inventati.org; helo=devianza.investici.org X-detected-operating-system: by eggs.gnu.org: First seen = 2020/07/25 06:46:30 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:253209 Archived-At: --Sig_/qhdSDt=oEbfDKGsOToy0VRb Content-Type: multipart/mixed; boundary="MP_/Hfs=BLzO_n8SDzKQtl6Cghz" --MP_/Hfs=BLzO_n8SDzKQtl6Cghz Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline > Hi, Matthew. Thanks so much for this. I have reviewed the patch > against 'master' (since it applies cleanly there, whereas it does not > quite apply cleanly to 'emacs-27'). It is very good; I have just > some minor comments below. Hi Karl. I'm flattered, thanks! I appreciate so much that you took the time to review my patch, and I eagerly followed your suggestions! You will find attached both a patch that applies to master, and one that applies to emacs-27... They are the same in term of changes. I'm still waiting a reply to the copyright assignment... But in the meantime we can freely discuss about the patch... > 1) It helps to include a summary line at the top of your commit > message, followed by a blank line. The summary line should be > limited to 50 characters or fewer, if possible. (This is all > documented in the "Commit messages" section in the 'CONTRIBUTE' file > in the top level of the Emacs source tree, by the way). In your > case, the Subject header of your email almost does the job -- we can > shorten it a bit to fit within 50 characters: >=20 > "Add ability to mark/unmark/delete all bookmarks" Thanks for pointing that out. Now that I read the 'CONTRIBUTE' file, I have some questions (by the way, I needed a remainder to read...): 1) I did commit a message with a summary line, as you described... [ Actually my line was the subject of the thread, yours (above) is better, hence I switched to your idea, thanks again ;) ] And indeed I use `git format-patch -1` as suggested in 'CONTRIBUTE' to produce a patch, but the command "strips" the summary line from the commit message and uses it as 'Subject:' in the patch, where it is prefixed with '[PATCH] ' if the option -k isn't also given... Once the patch is applied via `git am`, the 'Subject:' is put back in the commit message as summary, without the '[PATCH] ' prefix. So, I wonder if you used `git am` to apply the patch...? Could you tip me off, please? 2) With which quotes should I surround the variable/function names in the commit message? `' or '' or =E2=80=98=E2=80=99? I could not figure t= hat out... > 2) In the commit message, you don't need to repeat the filename ("* > lisp/bookmark.el") each time. You can just write it once, and then > underneath it show everything affected in that file. Taking the > first three entries in your original log message as an example: >=20 > * lisp/bookmark.el (bookmark-delete-all): New function to delete > all bookmarks. > * lisp/bookmark.el (bookmark-bmenu-mark-all): New function to mark > all bookmarks in the bookmark list buffer. > * lisp/bookmark.el (bookmark-bmenu-unmark-all): New function to > unmark all bookmarks in the bookmark list buffer. >=20 > ...they would instead be written like this: >=20 > * lisp/bookmark.el (bookmark-delete-all): New function to delete > all bookmarks. > (bookmark-bmenu-mark-all): New function to mark all bookmarks in > the bookmark list buffer.=20 > (bookmark-bmenu-unmark-all): New function to unmark all > bookmarks in the bookmark list buffer. >=20 > Quick digression: >=20 > You can use 'git log' to see this style used in past Emacs commits. [x] Don't repeat the file name each time in the commit message. ...And yes, I did take a look at the `git log`... > Better to call ARG something like NO-CONFIRM, so its name reflects > its purpose. > > And a suggestion: have the prompt say "Permanently delete all > bookmarks? " instead. In `bookmark-delete-all': [x] Chage ARG to NO-CONFIRM. [x] Prompt "Permanently delete all bookmarks? ". > Because of subtle assumptions associated with English word order, the > current prompt ("Delete all bookmarks permanently? ") implies that > the alternative might be to delete the bookmarks non-permanently. That's a very smart thought... I'm truly impressed! > Regarding the "FIXME" comment: that assumption is embedded throughout > the bookmark-bmenu-* code, so I think there's no need for the "FIXME" > (and indeed the comment may cause confusion, since its presence calls > the assumption into question). >=20 > It might be good to make a followup change in which we document the > last-line-is-empty assumption, but that's a separate change of course. [x] Remove the "FIXME" code comments. > >+ ;; FIXME: This assumes that the last line is empty. > >+ (while (not (eobp)) > These tests are a huge contribution -- thanks for taking the time to > write them. Following your guidelines is very instructing, Karl! I also: [x] Change `nameN' and `fileN' into `name-N' and `file-N' (i.e. name0 -> name-0) in all new functions and in the new test-list.bmk file. [x] Indent new functions to split long lines into shorter ones. [x] bookmark-tests.el (bookmark-test-bmenu-any-marks-list): New function to test `bookmark-bmenu-any-marks' with a list of bookmarks. > This patch looks good to me. I've tested it myself and it works as > advertised, and the new tests pass 'make check'. >=20 > If you have time to revise the patch slightly as per above (if you > agree with the comments, of course -- otherwise, let's discuss here) > that would be great. I see that Stefan has already sent you the > assignment paperwork. >=20 > Best regards, > -Karl Again, thank you very much Karl for all your effort reviewing my patch, and especially for your brilliant insights! I hope to get back soon with good news about the copyright assignment. Catch you later! --MP_/Hfs=BLzO_n8SDzKQtl6Cghz Content-Type: text/x-patch Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename=master-Add-ability-to-mark-unmark-delete-all-bookmarks.patch =46rom 26b3590648720466a0a558e7c85da4eb7126827e Mon Sep 17 00:00:00 2001 From: Matthew White Date: Thu, 23 Jul 2020 21:14:32 +0000 Subject: [PATCH] Add ability to mark/unmark/delete all bookmarks * lisp/bookmark.el (bookmark-delete-all): New function to delete all bookmarks. (bookmark-bmenu-mark-all): New function to mark all bookmarks in the bookmark list buffer. (bookmark-bmenu-unmark-all): New function to unmark all bookmarks in the bookmark list buffer. (bookmark-bmenu-delete-all): New function to mark for deletion all bookmarks in the bookmark list buffer. (bookmark-map): Map "D" to `bookmark-delete-all'. (bookmark-bmenu-mode-map): New mappping for "M" to `bookmark-bmenu-mark-all'. (bookmark-bmenu-mode-map): New mappping for "U" to `bookmark-bmenu-unmark-all'. (bookmark-bmenu-mode-map): New mappping for "D" to `bookmark-bmenu-delete-all'. (bookmark-bmenu-mark-all): New bookmark menu to `bookmark-delete-all'. (easy-menu-define): New bookmark menu to `bookmark-bmenu-mark-all'. (easy-menu-define): New bookmark menu to `bookmark-bmenu-unmark-all'. (easy-menu-define): New bookmark menu to `bookmark-bmenu-delete-all'. (bookmark-bmenu-select): Update docstring to include a reference to `bookmark-bmenu-mark-all'. (bookmark-bmenu-mode): Update docstring. Add/Update description: `bookmark-bmenu-mark-all', `bookmark-bmenu-delete-all', `bookmark-bmenu-execute-deletions', and `bookmark-bmenu-unmark-all'. * test/lisp/bookmark-resources/test-list.bmk: New bookmark file to test a list of bookmarks. * test/lisp/bookmark-tests.el (bookmark-tests-bookmark-file-list): New reference to the bookmark file used for testing a list of bookmarks. (bookmark-tests-bookmark-list-0, bookmark-tests-bookmark-list-1, bookmark-tests-bookmark-list-2): New cached values for testing a list of bookmark. (bookmark-tests-cache-timestamp-list): New variable to set `bookmark-bookmarks-timestamp'. (with-bookmark-test-list): New macro environment to test a list of bookmarks. (with-bookmark-test-file-list): New macro environment to test a list of bookmarks with example.txt. (with-bookmark-bmenu-test-list): New macro environment to test functions about a list of bookmarks from `bookmark-bmenu-list'. (bookmark-tests-all-names-list, bookmark-tests-get-bookmark-list, bookmark-tests-get-bookmark-record-list): New functions to test the records of the list of bookmarks. (bookmark-tests-make-record-list): New function to test the creation of a record from example.txt with a list of bookmarks loaded. (bookmark-tests-delete-all): New function to test `bookmark-delete-all'. (bookmark-test-bmenu-any-marks-list): New function to test `bookmark-bmenu-any-marks' with a list of bookmarks. (bookmark-test-bmenu-mark-all): New function to test `bookmark-bmenu-mark-all'. (bookmark-test-bmenu-unmark-all): New function to test `bookmark-bmenu-unmark-all'. (bookmark-test-bmenu-delete-all): New function to test `bookmark-bmenu-delete-all'. --- lisp/bookmark.el | 77 +++++++- test/lisp/bookmark-resources/test-list.bmk | 20 ++ test/lisp/bookmark-tests.el | 215 +++++++++++++++++++++ 3 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 test/lisp/bookmark-resources/test-list.bmk diff --git a/lisp/bookmark.el b/lisp/bookmark.el index de7d60f97e..870c41d5a8 100644 --- a/lisp/bookmark.el +++ b/lisp/bookmark.el @@ -200,6 +200,7 @@ A non-nil value may result in truncated bookmark names." (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) @@ -1374,6 +1375,22 @@ probably because we were called from there." (bookmark-save))) =20 =20 +;;;###autoload +(defun bookmark-delete-all (&optional no-confirm) + "Permanently delete all bookmarks. +Doesn't ask for confirmation if NO-CONFIRM is non-nil." + (interactive "P") + (when (or no-confirm + (yes-or-no-p "Permanently delete all bookmarks? ")) + (bookmark-maybe-load-default-file) + (setq bookmark-alist-modification-count + (+ bookmark-alist-modification-count (length bookmark-alist))) + (setq bookmark-alist nil) + (bookmark-bmenu-surreptitiously-rebuild-list) + (when (bookmark-time-to-save-p) + (bookmark-save)))) + + (defun bookmark-time-to-save-p (&optional final-time) "Return t if it is time to save bookmarks to disk, nil otherwise. Optional argument FINAL-TIME means this is being called when Emacs @@ -1600,12 +1617,15 @@ unique numeric suffixes \"<2>\", \"<3>\", etc." (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 "n" 'next-line) (define-key map "p" 'previous-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) @@ -1627,8 +1647,10 @@ unique numeric suffixes \"<2>\", \"<3>\", etc." ["Select Marked Bookmarks" bookmark-bmenu-select t] "---" ["Mark Bookmark" bookmark-bmenu-mark t] + ["Mark all Bookmarks" bookmark-bmenu-mark-all t] ["Unmark Bookmark" bookmark-bmenu-unmark t] ["Unmark Backwards" bookmark-bmenu-backup-unmark t] + ["Unmark all Bookmarks" bookmark-bmenu-unmark-all t] ["Toggle Display of Filenames" bookmark-bmenu-toggle-filenames t] ["Display Location of Bookmark" bookmark-bmenu-locate t] "---" @@ -1636,6 +1658,7 @@ unique numeric suffixes \"<2>\", \"<3>\", etc." ["Rename Bookmark" bookmark-bmenu-rename t] ["Relocate Bookmark's File" bookmark-bmenu-relocate t] ["Mark Bookmark for Deletion" bookmark-bmenu-delete t] + ["Mark all Bookmarks for Deletion" bookmark-bmenu-delete-all t] ["Delete Marked Bookmarks" bookmark-bmenu-execute-deletions t]) ("Annotations" ["Show Annotation for Current Bookmark" bookmark-bmenu-show-annotatio= n t] @@ -1748,6 +1771,7 @@ Letters do not insert themselves; instead, they are c= ommands. Bookmark names preceded by a \"*\" have annotations. \\ \\[bookmark-bmenu-mark] -- mark bookmark to be displayed. +\\[bookmark-bmenu-mark-all] -- mark all listed bookmarks to be displayed. \\[bookmark-bmenu-select] -- select bookmark of line point is on. Also show bookmarks marked using m in other windows. \\[bookmark-bmenu-toggle-filenames] -- toggle displaying of filenames (the= y may obscure long bookmark names). @@ -1764,13 +1788,15 @@ Bookmark names preceded by a \"*\" have annotations. \\[bookmark-bmenu-relocate] -- relocate this bookmark's file (prompts for = new file). \\[bookmark-bmenu-delete] -- mark this bookmark to be deleted, and move do= wn. \\[bookmark-bmenu-delete-backwards] -- mark this bookmark to be deleted, a= nd move up. -\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[b= ookmark-bmenu-delete]'. +\\[bookmark-bmenu-delete-all] -- mark all listed bookmarks as to be delete= d. +\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[b= ookmark-bmenu-delete]' or `\\[bookmark-bmenu-delete-all]'. \\[bookmark-bmenu-save] -- save the current bookmark list in the default f= ile. With a prefix arg, prompts for a file to save in. \\[bookmark-bmenu-load] -- load in a file of bookmarks (prompts for file.) \\[bookmark-bmenu-unmark] -- remove all kinds of marks from current line. With prefix argument, also move up one line. \\[bookmark-bmenu-backup-unmark] -- back up a line and remove marks. +\\[bookmark-bmenu-unmark-all] -- remove all kinds of marks from all listed= bookmarks. \\[bookmark-bmenu-show-annotation] -- show the annotation, if it exists, f= or the current bookmark in another buffer. \\[bookmark-bmenu-show-all-annotations] -- show the annotations of all boo= kmarks in another buffer. @@ -1937,9 +1963,23 @@ If the annotation does not exist, do nothing." (bookmark-bmenu-ensure-position)))) =20 =20 +(defun bookmark-bmenu-mark-all () + "Mark all listed bookmarks to be displayed by \\\\[bookmark-bmenu-select]." + (interactive) + (save-excursion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (while (not (eobp)) + (delete-char 1) + (insert ?>) + (forward-line 1)))))) + + (defun bookmark-bmenu-select () "Select this line's bookmark; also display bookmarks marked with `>'. -You can mark bookmarks with the \\\\[bookmark-bme= nu-mark] command." +You can mark bookmarks with the \\\\[bookmark-bme= nu-mark] or \\\\[bookmark-bmenu-mark-all] commands= ." (interactive) (let ((bmrk (bookmark-bmenu-bookmark)) (menu (current-buffer)) @@ -2108,6 +2148,20 @@ Optional BACKUP means move up." (bookmark-bmenu-ensure-position)) =20 =20 +(defun bookmark-bmenu-unmark-all () + "Cancel all requested operations on all listed bookmarks." + (interactive) + (save-excursion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (while (not (eobp)) + (delete-char 1) + (insert " ") + (forward-line 1)))))) + + (defun bookmark-bmenu-delete () "Mark bookmark on this line to be deleted. To carry out the deletions that you've marked, use \\\\[bookmark-bmenu-execute-deletions]." @@ -2133,6 +2187,22 @@ To carry out the deletions that you've marked, use \= \\\ (bookmark-bmenu-ensure-position)) =20 =20 +(defun bookmark-bmenu-delete-all () + "Mark all listed bookmarks as to be deleted. +To remove all deletion marks, use \\\\[bookmark-b= menu-unmark-all]. +To carry out the deletions that you've marked, use \\\\[bookmark-bmenu-execute-deletions]." + (interactive) + (save-excursion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (while (not (eobp)) + (delete-char 1) + (insert ?D) + (forward-line 1)))))) + + (defun bookmark-bmenu-execute-deletions () "Delete bookmarks flagged `D'." (interactive) @@ -2292,6 +2362,9 @@ strings returned are not." (bindings--define-key map [delete] '(menu-item "Delete Bookmark..." bookmark-delete :help "Delete a bookmark from the bookmark list")) + (bindings--define-key map [delete-all] + '(menu-item "Delete all Bookmarks..." bookmark-delete-all + :help "Delete all bookmarks from the bookmark list")) (bindings--define-key map [rename] '(menu-item "Rename Bookmark..." bookmark-rename :help "Change the name of a bookmark")) diff --git a/test/lisp/bookmark-resources/test-list.bmk b/test/lisp/bookmar= k-resources/test-list.bmk new file mode 100644 index 0000000000..696d64979b --- /dev/null +++ b/test/lisp/bookmark-resources/test-list.bmk @@ -0,0 +1,20 @@ +;;;; Emacs Bookmark Format Version 1 ;;;; -*- coding: utf-8-emacs -*- +;;; This format is meant to be slightly human-readable; +;;; nevertheless, you probably don't want to edit it. +;;; -*- End Of Bookmark File Format Version Stamp -*- +(("name-0" + (filename . "/some/file-0") + (front-context-string . "abc") + (rear-context-string . "def") + (position . 3)) +("name-1" + (filename . "/some/file-1") + (front-context-string . "abc") + (rear-context-string . "def") + (position . 3)) +("name-2" + (filename . "/some/file-2") + (front-context-string . "abc") + (rear-context-string . "def") + (position . 3)) +) diff --git a/test/lisp/bookmark-tests.el b/test/lisp/bookmark-tests.el index b9c6ff9c54..d5f7f24317 100644 --- a/test/lisp/bookmark-tests.el +++ b/test/lisp/bookmark-tests.el @@ -83,6 +83,70 @@ the lexically-bound variable `buffer'." ,@body) (kill-buffer buffer)))) =20 +(defvar bookmark-tests-bookmark-file-list + (expand-file-name "test-list.bmk" bookmark-tests-data-dir) + "Bookmark file used for testing a list of bookmarks.") + +;; The values below should match `bookmark-tests-bookmark-file-list' +;; content. We cache these values to speed up tests. +(eval-and-compile ; needed by `with-bookmark-test-list' macro + (defvar bookmark-tests-bookmark-list-0 '("name-0" + (filename . "/some/file-0") + (front-context-string . "ghi") + (rear-context-string . "jkl") + (position . 4)) + "Cached value used in bookmark-tests.el.")) + +;; The values below should match `bookmark-tests-bookmark-file-list' +;; content. We cache these values to speed up tests. +(eval-and-compile ; needed by `with-bookmark-test-list' macro + (defvar bookmark-tests-bookmark-list-1 '("name-1" + (filename . "/some/file-1") + (front-context-string . "mno") + (rear-context-string . "pqr") + (position . 5)) + "Cached value used in bookmark-tests.el.")) + +;; The values below should match `bookmark-tests-bookmark-file-list' +;; content. We cache these values to speed up tests. +(eval-and-compile ; needed by `with-bookmark-test-list' macro + (defvar bookmark-tests-bookmark-list-2 '("name-2" + (filename . "/some/file-2") + (front-context-string . "stu") + (rear-context-string . "vwx") + (position . 6)) + "Cached value used in bookmark-tests.el.")) + +(defvar bookmark-tests-cache-timestamp-list + (cons bookmark-tests-bookmark-file-list + (nth 5 (file-attributes + bookmark-tests-bookmark-file-list))) + "Cached value used in bookmark-tests.el.") + +(defmacro with-bookmark-test-list (&rest body) + "Create environment for testing bookmark.el and evaluate BODY. +Ensure a clean environment for testing, and do not change user +data when running tests interactively." + `(with-temp-buffer + (let ((bookmark-alist (quote (,(copy-sequence bookmark-tests-bookmark= -list-0) + ,(copy-sequence bookmark-tests-bookmark= -list-1) + ,(copy-sequence bookmark-tests-bookmark= -list-2)))) + (bookmark-default-file bookmark-tests-bookmark-file-list) + (bookmark-bookmarks-timestamp bookmark-tests-cache-timestamp-li= st) + bookmark-save-flag) + ,@body))) + +(defmacro with-bookmark-test-file-list (&rest body) + "Create environment for testing bookmark.el and evaluate BODY. +Same as `with-bookmark-test-list' but also opens the resource file +example.txt in a buffer, which can be accessed by callers through +the lexically-bound variable `buffer'." + `(let ((buffer (find-file-noselect bookmark-tests-example-file))) + (unwind-protect + (with-bookmark-test-list + ,@body) + (kill-buffer buffer)))) + (ert-deftest bookmark-tests-all-names () (with-bookmark-test (should (equal (bookmark-all-names) '("name"))))) @@ -95,6 +159,30 @@ the lexically-bound variable `buffer'." (with-bookmark-test (should (equal (bookmark-get-bookmark-record "name") (cdr bookmark-test= s-bookmark))))) =20 +(ert-deftest bookmark-tests-all-names-list () + (with-bookmark-test-list + (should (equal (bookmark-all-names) '("name-0" + "name-1" + "name-2"))))) + +(ert-deftest bookmark-tests-get-bookmark-list () + (with-bookmark-test-list + (should (equal (bookmark-get-bookmark "name-0") + bookmark-tests-bookmark-list-0)) + (should (equal (bookmark-get-bookmark "name-1") + bookmark-tests-bookmark-list-1)) + (should (equal (bookmark-get-bookmark "name-2") + bookmark-tests-bookmark-list-2)))) + +(ert-deftest bookmark-tests-get-bookmark-record-list () + (with-bookmark-test-list + (should (equal (bookmark-get-bookmark-record "name-0") + (cdr bookmark-tests-bookmark-list-0))) + (should (equal (bookmark-get-bookmark-record "name-1") + (cdr bookmark-tests-bookmark-list-1))) + (should (equal (bookmark-get-bookmark-record "name-2") + (cdr bookmark-tests-bookmark-list-2))))) + (ert-deftest bookmark-tests-record-getters-and-setters-new () (with-temp-buffer (let* ((buffer-file-name "test") @@ -130,6 +218,19 @@ the lexically-bound variable `buffer'." ;; calling twice gives same record (should (equal (bookmark-make-record) record)))))) =20 +(ert-deftest bookmark-tests-make-record-list () + (with-bookmark-test-file-list + (let* ((record `("example.txt" (filename . ,bookmark-tests-example-file) + (front-context-string . "is text file is ") + (rear-context-string) + (position . 3) + (defaults "example.txt")))) + (with-current-buffer buffer + (goto-char 3) + (should (equal (bookmark-make-record) record)) + ;; calling twice gives same record + (should (equal (bookmark-make-record) record)))))) + (ert-deftest bookmark-tests-make-record-function () (with-bookmark-test (let ((buffer-file-name "test")) @@ -267,6 +368,11 @@ the lexically-bound variable `buffer'." (bookmark-delete "name") (should (equal bookmark-alist nil)))) =20 +(ert-deftest bookmark-tests-delete-all () + (with-bookmark-test-list + (bookmark-delete-all t) + (should (equal bookmark-alist nil)))) + (defmacro with-bookmark-test-save-load (&rest body) "Create environment for testing bookmark.el and evaluate BODY. Same as `with-bookmark-test' but also sets a temporary @@ -340,6 +446,18 @@ testing `bookmark-bmenu-list'." ,@body) (kill-buffer bookmark-bmenu-buffer))))) =20 +(defmacro with-bookmark-bmenu-test-list (&rest body) + "Create environment for testing `bookmark-bmenu-list' and evaluate BODY. +Same as `with-bookmark-test-list' but with additions suitable for +testing `bookmark-bmenu-list'." + `(with-bookmark-test-list + (let ((bookmark-bmenu-buffer "*Bookmark List - Testing*")) + (unwind-protect + (save-window-excursion + (bookmark-bmenu-list) + ,@body) + (kill-buffer bookmark-bmenu-buffer))))) + (ert-deftest bookmark-test-bmenu-edit-annotation/show-annotation () (with-bookmark-bmenu-test (bookmark-set-annotation "name" "foo") @@ -402,6 +520,52 @@ testing `bookmark-bmenu-list'." (beginning-of-line) (should (bookmark-bmenu-any-marks)))) =20 +(ert-deftest bookmark-test-bmenu-mark-all () + (with-bookmark-bmenu-test-list + (let ((here (point-max))) + ;; Expect to not move the point + (goto-char here) + (bookmark-bmenu-mark-all) + (should (equal here (point))) + ;; Verify that all bookmarks are marked + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark))))))) + +(ert-deftest bookmark-test-bmenu-any-marks-list () + (with-bookmark-bmenu-test-list + ;; Mark just the second item + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (forward-line 1) + (bookmark-bmenu-mark) + ;; Verify that only the second item is marked + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + ;; There should be at least one mark + (should (bookmark-bmenu-any-marks)))) + (ert-deftest bookmark-test-bmenu-unmark () (with-bookmark-bmenu-test (bookmark-bmenu-mark) @@ -410,12 +574,63 @@ testing `bookmark-bmenu-list'." (beginning-of-line) (should (looking-at "^ ")))) =20 +(ert-deftest bookmark-test-bmenu-unmark-all () + (with-bookmark-bmenu-test-list + (bookmark-bmenu-mark-all) + (let ((here (point-max))) + ;; Expect to not move the point + (goto-char here) + (bookmark-bmenu-unmark-all) + (should (equal here (point))) + ;; Verify that all bookmarks are unmarked + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark))))))) + (ert-deftest bookmark-test-bmenu-delete () (with-bookmark-bmenu-test (bookmark-bmenu-delete) (bookmark-bmenu-execute-deletions) (should (equal (length bookmark-alist) 0)))) =20 +(ert-deftest bookmark-test-bmenu-delete-all () + (with-bookmark-bmenu-test-list + ;; Verify that unmarked bookmarks aren't deleted + (bookmark-bmenu-execute-deletions) + (should-not (eq bookmark-alist nil)) + (let ((here (point-max))) + ;; Expect to not move the point + (goto-char here) + (bookmark-bmenu-delete-all) + (should (equal here (point))) + ;; Verify that all bookmarks are marked for deletion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^D ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^D ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^D ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + ;; Verify that all bookmarks are deleted + (bookmark-bmenu-execute-deletions) + (should (eq bookmark-alist nil))))) + (ert-deftest bookmark-test-bmenu-locate () (let (msg) (cl-letf (((symbol-function 'message) --=20 2.26.2 --MP_/Hfs=BLzO_n8SDzKQtl6Cghz Content-Type: text/x-patch Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename=emacs-27-Add-ability-to-mark-unmark-delete-all-bookmarks.patch =46rom 3e7dd3655b3e28e47be88f60f3bb5f03f251e9ee Mon Sep 17 00:00:00 2001 From: Matthew White Date: Thu, 23 Jul 2020 21:14:32 +0000 Subject: [PATCH] Add ability to mark/unmark/delete all bookmarks * lisp/bookmark.el (bookmark-delete-all): New function to delete all bookmarks. (bookmark-bmenu-mark-all): New function to mark all bookmarks in the bookmark list buffer. (bookmark-bmenu-unmark-all): New function to unmark all bookmarks in the bookmark list buffer. (bookmark-bmenu-delete-all): New function to mark for deletion all bookmarks in the bookmark list buffer. (bookmark-map): Map "D" to `bookmark-delete-all'. (bookmark-bmenu-mode-map): New mappping for "M" to `bookmark-bmenu-mark-all'. (bookmark-bmenu-mode-map): New mappping for "U" to `bookmark-bmenu-unmark-all'. (bookmark-bmenu-mode-map): New mappping for "D" to `bookmark-bmenu-delete-all'. (bookmark-bmenu-mark-all): New bookmark menu to `bookmark-delete-all'. (easy-menu-define): New bookmark menu to `bookmark-bmenu-mark-all'. (easy-menu-define): New bookmark menu to `bookmark-bmenu-unmark-all'. (easy-menu-define): New bookmark menu to `bookmark-bmenu-delete-all'. (bookmark-bmenu-select): Update docstring to include a reference to `bookmark-bmenu-mark-all'. (bookmark-bmenu-mode): Update docstring. Add/Update description: `bookmark-bmenu-mark-all', `bookmark-bmenu-delete-all', `bookmark-bmenu-execute-deletions', and `bookmark-bmenu-unmark-all'. * test/lisp/bookmark-resources/test-list.bmk: New bookmark file to test a list of bookmarks. * test/lisp/bookmark-tests.el (bookmark-tests-bookmark-file-list): New reference to the bookmark file used for testing a list of bookmarks. (bookmark-tests-bookmark-list-0, bookmark-tests-bookmark-list-1, bookmark-tests-bookmark-list-2): New cached values for testing a list of bookmark. (bookmark-tests-cache-timestamp-list): New variable to set `bookmark-bookmarks-timestamp'. (with-bookmark-test-list): New macro environment to test a list of bookmarks. (with-bookmark-test-file-list): New macro environment to test a list of bookmarks with example.txt. (with-bookmark-bmenu-test-list): New macro environment to test functions about a list of bookmarks from `bookmark-bmenu-list'. (bookmark-tests-all-names-list, bookmark-tests-get-bookmark-list, bookmark-tests-get-bookmark-record-list): New functions to test the records of the list of bookmarks. (bookmark-tests-make-record-list): New function to test the creation of a record from example.txt with a list of bookmarks loaded. (bookmark-tests-delete-all): New function to test `bookmark-delete-all'. (bookmark-test-bmenu-any-marks-list): New function to test `bookmark-bmenu-any-marks' with a list of bookmarks. (bookmark-test-bmenu-mark-all): New function to test `bookmark-bmenu-mark-all'. (bookmark-test-bmenu-unmark-all): New function to test `bookmark-bmenu-unmark-all'. (bookmark-test-bmenu-delete-all): New function to test `bookmark-bmenu-delete-all'. --- lisp/bookmark.el | 77 +++++++- test/lisp/bookmark-resources/test-list.bmk | 20 ++ test/lisp/bookmark-tests.el | 215 +++++++++++++++++++++ 3 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 test/lisp/bookmark-resources/test-list.bmk diff --git a/lisp/bookmark.el b/lisp/bookmark.el index e69d9f529c..c45a5103fe 100644 --- a/lisp/bookmark.el +++ b/lisp/bookmark.el @@ -200,6 +200,7 @@ A non-nil value may result in truncated bookmark names." (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) @@ -1372,6 +1373,22 @@ probably because we were called from there." (bookmark-save))) =20 =20 +;;;###autoload +(defun bookmark-delete-all (&optional no-confirm) + "Permanently delete all bookmarks. +Doesn't ask for confirmation if NO-CONFIRM is non-nil." + (interactive "P") + (when (or no-confirm + (yes-or-no-p "Permanently delete all bookmarks? ")) + (bookmark-maybe-load-default-file) + (setq bookmark-alist-modification-count + (+ bookmark-alist-modification-count (length bookmark-alist))) + (setq bookmark-alist nil) + (bookmark-bmenu-surreptitiously-rebuild-list) + (when (bookmark-time-to-save-p) + (bookmark-save)))) + + (defun bookmark-time-to-save-p (&optional final-time) "Return t if it is time to save bookmarks to disk, nil otherwise. Optional argument FINAL-TIME means this is being called when Emacs @@ -1598,12 +1615,15 @@ unique numeric suffixes \"<2>\", \"<3>\", etc." (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 "n" 'next-line) (define-key map "p" 'previous-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) @@ -1625,8 +1645,10 @@ unique numeric suffixes \"<2>\", \"<3>\", etc." ["Select Marked Bookmarks" bookmark-bmenu-select t] "---" ["Mark Bookmark" bookmark-bmenu-mark t] + ["Mark all Bookmarks" bookmark-bmenu-mark-all t] ["Unmark Bookmark" bookmark-bmenu-unmark t] ["Unmark Backwards" bookmark-bmenu-backup-unmark t] + ["Unmark all Bookmarks" bookmark-bmenu-unmark-all t] ["Toggle Display of Filenames" bookmark-bmenu-toggle-filenames t] ["Display Location of Bookmark" bookmark-bmenu-locate t] "---" @@ -1634,6 +1656,7 @@ unique numeric suffixes \"<2>\", \"<3>\", etc." ["Rename Bookmark" bookmark-bmenu-rename t] ["Relocate Bookmark's File" bookmark-bmenu-relocate t] ["Mark Bookmark for Deletion" bookmark-bmenu-delete t] + ["Mark all Bookmarks for Deletion" bookmark-bmenu-delete-all t] ["Delete Marked Bookmarks" bookmark-bmenu-execute-deletions t]) ("Annotations" ["Show Annotation for Current Bookmark" bookmark-bmenu-show-annotatio= n t] @@ -1746,6 +1769,7 @@ Letters do not insert themselves; instead, they are c= ommands. Bookmark names preceded by a \"*\" have annotations. \\ \\[bookmark-bmenu-mark] -- mark bookmark to be displayed. +\\[bookmark-bmenu-mark-all] -- mark all listed bookmarks to be displayed. \\[bookmark-bmenu-select] -- select bookmark of line point is on. Also show bookmarks marked using m in other windows. \\[bookmark-bmenu-toggle-filenames] -- toggle displaying of filenames (the= y may obscure long bookmark names). @@ -1762,13 +1786,15 @@ Bookmark names preceded by a \"*\" have annotations. \\[bookmark-bmenu-relocate] -- relocate this bookmark's file (prompts for = new file). \\[bookmark-bmenu-delete] -- mark this bookmark to be deleted, and move do= wn. \\[bookmark-bmenu-delete-backwards] -- mark this bookmark to be deleted, a= nd move up. -\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[b= ookmark-bmenu-delete]'. +\\[bookmark-bmenu-delete-all] -- mark all listed bookmarks as to be delete= d. +\\[bookmark-bmenu-execute-deletions] -- delete bookmarks marked with `\\[b= ookmark-bmenu-delete]' or `\\[bookmark-bmenu-delete-all]'. \\[bookmark-bmenu-save] -- save the current bookmark list in the default f= ile. With a prefix arg, prompts for a file to save in. \\[bookmark-bmenu-load] -- load in a file of bookmarks (prompts for file.) \\[bookmark-bmenu-unmark] -- remove all kinds of marks from current line. With prefix argument, also move up one line. \\[bookmark-bmenu-backup-unmark] -- back up a line and remove marks. +\\[bookmark-bmenu-unmark-all] -- remove all kinds of marks from all listed= bookmarks. \\[bookmark-bmenu-show-annotation] -- show the annotation, if it exists, f= or the current bookmark in another buffer. \\[bookmark-bmenu-show-all-annotations] -- show the annotations of all boo= kmarks in another buffer. @@ -1935,9 +1961,23 @@ If the annotation does not exist, do nothing." (bookmark-bmenu-ensure-position)))) =20 =20 +(defun bookmark-bmenu-mark-all () + "Mark all listed bookmarks to be displayed by \\\\[bookmark-bmenu-select]." + (interactive) + (save-excursion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (while (not (eobp)) + (delete-char 1) + (insert ?>) + (forward-line 1)))))) + + (defun bookmark-bmenu-select () "Select this line's bookmark; also display bookmarks marked with `>'. -You can mark bookmarks with the \\\\[bookmark-bme= nu-mark] command." +You can mark bookmarks with the \\\\[bookmark-bme= nu-mark] or \\\\[bookmark-bmenu-mark-all] commands= ." (interactive) (let ((bmrk (bookmark-bmenu-bookmark)) (menu (current-buffer)) @@ -2106,6 +2146,20 @@ Optional BACKUP means move up." (bookmark-bmenu-ensure-position)) =20 =20 +(defun bookmark-bmenu-unmark-all () + "Cancel all requested operations on all listed bookmarks." + (interactive) + (save-excursion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (while (not (eobp)) + (delete-char 1) + (insert " ") + (forward-line 1)))))) + + (defun bookmark-bmenu-delete () "Mark bookmark on this line to be deleted. To carry out the deletions that you've marked, use \\\\[bookmark-bmenu-execute-deletions]." @@ -2131,6 +2185,22 @@ To carry out the deletions that you've marked, use \= \\\ (bookmark-bmenu-ensure-position)) =20 =20 +(defun bookmark-bmenu-delete-all () + "Mark all listed bookmarks as to be deleted. +To remove all deletion marks, use \\\\[bookmark-b= menu-unmark-all]. +To carry out the deletions that you've marked, use \\\\[bookmark-bmenu-execute-deletions]." + (interactive) + (save-excursion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (with-buffer-modified-unmodified + (let ((inhibit-read-only t)) + (while (not (eobp)) + (delete-char 1) + (insert ?D) + (forward-line 1)))))) + + (defun bookmark-bmenu-execute-deletions () "Delete bookmarks flagged `D'." (interactive) @@ -2290,6 +2360,9 @@ strings returned are not." (bindings--define-key map [delete] '(menu-item "Delete Bookmark..." bookmark-delete :help "Delete a bookmark from the bookmark list")) + (bindings--define-key map [delete-all] + '(menu-item "Delete all Bookmarks..." bookmark-delete-all + :help "Delete all bookmarks from the bookmark list")) (bindings--define-key map [rename] '(menu-item "Rename Bookmark..." bookmark-rename :help "Change the name of a bookmark")) diff --git a/test/lisp/bookmark-resources/test-list.bmk b/test/lisp/bookmar= k-resources/test-list.bmk new file mode 100644 index 0000000000..696d64979b --- /dev/null +++ b/test/lisp/bookmark-resources/test-list.bmk @@ -0,0 +1,20 @@ +;;;; Emacs Bookmark Format Version 1 ;;;; -*- coding: utf-8-emacs -*- +;;; This format is meant to be slightly human-readable; +;;; nevertheless, you probably don't want to edit it. +;;; -*- End Of Bookmark File Format Version Stamp -*- +(("name-0" + (filename . "/some/file-0") + (front-context-string . "abc") + (rear-context-string . "def") + (position . 3)) +("name-1" + (filename . "/some/file-1") + (front-context-string . "abc") + (rear-context-string . "def") + (position . 3)) +("name-2" + (filename . "/some/file-2") + (front-context-string . "abc") + (rear-context-string . "def") + (position . 3)) +) diff --git a/test/lisp/bookmark-tests.el b/test/lisp/bookmark-tests.el index 7e0384b724..726db52943 100644 --- a/test/lisp/bookmark-tests.el +++ b/test/lisp/bookmark-tests.el @@ -82,6 +82,70 @@ the lexically-bound variable `buffer'." ,@body) (kill-buffer buffer)))) =20 +(defvar bookmark-tests-bookmark-file-list + (expand-file-name "test-list.bmk" bookmark-tests-data-dir) + "Bookmark file used for testing a list of bookmarks.") + +;; The values below should match `bookmark-tests-bookmark-file-list' +;; content. We cache these values to speed up tests. +(eval-and-compile ; needed by `with-bookmark-test-list' macro + (defvar bookmark-tests-bookmark-list-0 '("name-0" + (filename . "/some/file-0") + (front-context-string . "ghi") + (rear-context-string . "jkl") + (position . 4)) + "Cached value used in bookmark-tests.el.")) + +;; The values below should match `bookmark-tests-bookmark-file-list' +;; content. We cache these values to speed up tests. +(eval-and-compile ; needed by `with-bookmark-test-list' macro + (defvar bookmark-tests-bookmark-list-1 '("name-1" + (filename . "/some/file-1") + (front-context-string . "mno") + (rear-context-string . "pqr") + (position . 5)) + "Cached value used in bookmark-tests.el.")) + +;; The values below should match `bookmark-tests-bookmark-file-list' +;; content. We cache these values to speed up tests. +(eval-and-compile ; needed by `with-bookmark-test-list' macro + (defvar bookmark-tests-bookmark-list-2 '("name-2" + (filename . "/some/file-2") + (front-context-string . "stu") + (rear-context-string . "vwx") + (position . 6)) + "Cached value used in bookmark-tests.el.")) + +(defvar bookmark-tests-cache-timestamp-list + (cons bookmark-tests-bookmark-file-list + (nth 5 (file-attributes + bookmark-tests-bookmark-file-list))) + "Cached value used in bookmark-tests.el.") + +(defmacro with-bookmark-test-list (&rest body) + "Create environment for testing bookmark.el and evaluate BODY. +Ensure a clean environment for testing, and do not change user +data when running tests interactively." + `(with-temp-buffer + (let ((bookmark-alist (quote (,(copy-sequence bookmark-tests-bookmark= -list-0) + ,(copy-sequence bookmark-tests-bookmark= -list-1) + ,(copy-sequence bookmark-tests-bookmark= -list-2)))) + (bookmark-default-file bookmark-tests-bookmark-file-list) + (bookmark-bookmarks-timestamp bookmark-tests-cache-timestamp-li= st) + bookmark-save-flag) + ,@body))) + +(defmacro with-bookmark-test-file-list (&rest body) + "Create environment for testing bookmark.el and evaluate BODY. +Same as `with-bookmark-test-list' but also opens the resource file +example.txt in a buffer, which can be accessed by callers through +the lexically-bound variable `buffer'." + `(let ((buffer (find-file-noselect bookmark-tests-example-file))) + (unwind-protect + (with-bookmark-test-list + ,@body) + (kill-buffer buffer)))) + (ert-deftest bookmark-tests-all-names () (with-bookmark-test (should (equal (bookmark-all-names) '("name"))))) @@ -94,6 +158,30 @@ the lexically-bound variable `buffer'." (with-bookmark-test (should (equal (bookmark-get-bookmark-record "name") (cdr bookmark-test= s-bookmark))))) =20 +(ert-deftest bookmark-tests-all-names-list () + (with-bookmark-test-list + (should (equal (bookmark-all-names) '("name-0" + "name-1" + "name-2"))))) + +(ert-deftest bookmark-tests-get-bookmark-list () + (with-bookmark-test-list + (should (equal (bookmark-get-bookmark "name-0") + bookmark-tests-bookmark-list-0)) + (should (equal (bookmark-get-bookmark "name-1") + bookmark-tests-bookmark-list-1)) + (should (equal (bookmark-get-bookmark "name-2") + bookmark-tests-bookmark-list-2)))) + +(ert-deftest bookmark-tests-get-bookmark-record-list () + (with-bookmark-test-list + (should (equal (bookmark-get-bookmark-record "name-0") + (cdr bookmark-tests-bookmark-list-0))) + (should (equal (bookmark-get-bookmark-record "name-1") + (cdr bookmark-tests-bookmark-list-1))) + (should (equal (bookmark-get-bookmark-record "name-2") + (cdr bookmark-tests-bookmark-list-2))))) + (ert-deftest bookmark-tests-record-getters-and-setters-new () (with-temp-buffer (let* ((buffer-file-name "test") @@ -129,6 +217,19 @@ the lexically-bound variable `buffer'." ;; calling twice gives same record (should (equal (bookmark-make-record) record)))))) =20 +(ert-deftest bookmark-tests-make-record-list () + (with-bookmark-test-file-list + (let* ((record `("example.txt" (filename . ,bookmark-tests-example-file) + (front-context-string . "is text file is ") + (rear-context-string) + (position . 3) + (defaults "example.txt")))) + (with-current-buffer buffer + (goto-char 3) + (should (equal (bookmark-make-record) record)) + ;; calling twice gives same record + (should (equal (bookmark-make-record) record)))))) + (ert-deftest bookmark-tests-make-record-function () (with-bookmark-test (let ((buffer-file-name "test")) @@ -266,6 +367,11 @@ the lexically-bound variable `buffer'." (bookmark-delete "name") (should (equal bookmark-alist nil)))) =20 +(ert-deftest bookmark-tests-delete-all () + (with-bookmark-test-list + (bookmark-delete-all t) + (should (equal bookmark-alist nil)))) + (defmacro with-bookmark-test-save-load (&rest body) "Create environment for testing bookmark.el and evaluate BODY. Same as `with-bookmark-test' but also sets a temporary @@ -339,6 +445,18 @@ testing `bookmark-bmenu-list'." ,@body) (kill-buffer bookmark-bmenu-buffer))))) =20 +(defmacro with-bookmark-bmenu-test-list (&rest body) + "Create environment for testing `bookmark-bmenu-list' and evaluate BODY. +Same as `with-bookmark-test-list' but with additions suitable for +testing `bookmark-bmenu-list'." + `(with-bookmark-test-list + (let ((bookmark-bmenu-buffer "*Bookmark List - Testing*")) + (unwind-protect + (save-window-excursion + (bookmark-bmenu-list) + ,@body) + (kill-buffer bookmark-bmenu-buffer))))) + (ert-deftest bookmark-bmenu.enu-edit-annotation/show-annotation () (with-bookmark-bmenu-test (bookmark-set-annotation "name" "foo") @@ -362,5 +480,102 @@ testing `bookmark-bmenu-list'." (should (equal (buffer-name (current-buffer)) bookmark-bmenu-buffer)) (should (looking-at "name")))) =20 +(ert-deftest bookmark-test-bmenu-mark-all () + (with-bookmark-bmenu-test-list + (let ((here (point-max))) + ;; Expect to not move the point + (goto-char here) + (bookmark-bmenu-mark-all) + (should (equal here (point))) + ;; Verify that all bookmarks are marked + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark))))))) + +(ert-deftest bookmark-test-bmenu-any-marks-list () + (with-bookmark-bmenu-test-list + ;; Mark just the second item + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (forward-line 1) + (bookmark-bmenu-mark) + ;; Verify that only the second item is marked + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^> ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + ;; There should be at least one mark + (should (bookmark-bmenu-any-marks)))) + +(ert-deftest bookmark-test-bmenu-unmark-all () + (with-bookmark-bmenu-test-list + (bookmark-bmenu-mark-all) + (let ((here (point-max))) + ;; Expect to not move the point + (goto-char here) + (bookmark-bmenu-unmark-all) + (should (equal here (point))) + ;; Verify that all bookmarks are unmarked + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^ ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark))))))) + +(ert-deftest bookmark-test-bmenu-delete-all () + (with-bookmark-bmenu-test-list + ;; Verify that unmarked bookmarks aren't deleted + (bookmark-bmenu-execute-deletions) + (should-not (eq bookmark-alist nil)) + (let ((here (point-max))) + ;; Expect to not move the point + (goto-char here) + (bookmark-bmenu-delete-all) + (should (equal here (point))) + ;; Verify that all bookmarks are marked for deletion + (goto-char (point-min)) + (bookmark-bmenu-ensure-position) + (should (looking-at "^D ")) + (should (equal bookmark-tests-bookmark-list-0 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^D ")) + (should (equal bookmark-tests-bookmark-list-1 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + (forward-line 1) + (should (looking-at "^D ")) + (should (equal bookmark-tests-bookmark-list-2 + (bookmark-get-bookmark (bookmark-bmenu-bookmark)))) + ;; Verify that all bookmarks are deleted + (bookmark-bmenu-execute-deletions) + (should (eq bookmark-alist nil))))) + (provide 'bookmark-tests) ;;; bookmark-tests.el ends here --=20 2.26.2 --MP_/Hfs=BLzO_n8SDzKQtl6Cghz-- --Sig_/qhdSDt=oEbfDKGsOToy0VRb Content-Type: application/pgp-signature Content-Description: OpenPGP digital signature -----BEGIN PGP SIGNATURE----- iQEzBAEBCAAdFiEEHleiF1SoBpqVdUvfw5wJ3TZNsgAFAl8cDXoACgkQw5wJ3TZN sgCATwf/ag/j0iuxWWXJLc8NP6KIGbuVg0yujfIo6I7WSjI7EzRCY2jD2tbmXVqA mUlOELnczPOzdAFMyCy4YKiLnjaX96yaKsL7yAlZEc99eE1+PmxwK/W00jB4d5o9 hK7b2ZBtclhB7SfY+wXc8hw1UwFJtwrpUprwdpLYVj/6YuM0HpxrQe1GEFudQls6 +SYvLNYH6tqyUr0flu6ugbXxK/VaTgHoDMCzmxYqOuwYk/0ka4YFpK3vxBbdc/FL t8SPTwNSuR9mEVAwcgOlL14dvOwRy1FUN/7Rgb5rl3m3XI7FXuiPEpUHM7758T0/ I8/cI2hjupvkXtYbEhvfRBlfyioNzg== =2uAQ -----END PGP SIGNATURE----- --Sig_/qhdSDt=oEbfDKGsOToy0VRb--