[PATCH] emacs: Use `cl-lib' instead of deprecated `cl'

William Casarin jb55 at jb55.com
Thu Apr 16 10:27:32 PDT 2020


From: Jonas Bernoulli <jonas at bernoul.li>

Starting with Emacs 27 the old `cl' implementation is finally
considered obsolete.  Previously its use was strongly discouraged
at run-time but one was still allowed to use it at compile-time.

For the most part the transition is very simple and boils down to
adding the "cl-" prefix to some symbols.  A few replacements do not
follow that simple pattern; e.g. `first' is replaced with `car',
even though the alias `cl-first' exists, because the latter is not
idiomatic emacs-lisp.

In a few cases we start using `pcase-let' or `pcase-lambda' instead
of renaming e.g. `first' to `car'.  That way we can remind the reader
of the meaning of the various parts of the data that is being
deconstructed.

An obsolete `lexical-let' and a `lexical-let*' are replaced with their
regular variants `let' and `let*' even though we do not at the same
time enable `lexical-binding' for that file.  That is the right thing
to do because it does not actually make a difference in those cases
whether lexical bindings are used or not, and because this should be
enabled in a separate commit.

We need to explicitly depend on the `cl-lib' package because Emacs
24.1 and 24.2 lack that library.  When using these releases we end
up using the backport from GNU Elpa.

We need to explicitly require the `pcase' library because
`pcase-dolist' was not autoloaded until Emacs 25.1.
---

Thanks Jonas!

I couldn't get this patch to cleanly apply, so I've rebased it on master
for anyone who wants to test.

Cheers,
Will

 emacs/notmuch-company.el     |   5 +-
 emacs/notmuch-draft.el       |   2 +-
 emacs/notmuch-hello.el       | 147 ++++++++++++++++++-----------------
 emacs/notmuch-jump.el        |  45 +++++------
 emacs/notmuch-lib.el         |  18 ++---
 emacs/notmuch-maildir-fcc.el |  35 +++++----
 emacs/notmuch-mua.el         |  76 +++++++++---------
 emacs/notmuch-parser.el      |  18 ++---
 emacs/notmuch-pkg.el.tmpl    |   3 +-
 emacs/notmuch-show.el        | 103 ++++++++++++------------
 emacs/notmuch-tag.el         |  45 ++++++-----
 emacs/notmuch-tree.el        |  20 ++---
 emacs/notmuch.el             |  62 +++++++--------
 test/test-lib.el             |   2 +-
 14 files changed, 292 insertions(+), 289 deletions(-)

diff --git a/emacs/notmuch-company.el b/emacs/notmuch-company.el
index 3e12e7a9..ac998f9b 100644
--- a/emacs/notmuch-company.el
+++ b/emacs/notmuch-company.el
@@ -27,7 +27,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
+
 (require 'notmuch-lib)
 
 (defvar notmuch-company-last-prefix nil)
@@ -65,7 +66,7 @@
   (require 'company)
   (let ((case-fold-search t)
 	(completion-ignore-case t))
-    (case command
+    (cl-case command
       (interactive (company-begin-backend 'notmuch-company))
       (prefix (and (derived-mode-p 'message-mode)
 		   (looking-back (concat notmuch-address-completion-headers-regexp ".*")
diff --git a/emacs/notmuch-draft.el b/emacs/notmuch-draft.el
index e22e0d16..504b33be 100644
--- a/emacs/notmuch-draft.el
+++ b/emacs/notmuch-draft.el
@@ -152,7 +152,7 @@ Used when a new version is saved, or the message is sent."
   "Checks if we should save a message that should be encrypted.
 
 `notmuch-draft-save-plaintext' controls the behaviour."
-  (case notmuch-draft-save-plaintext
+  (cl-case notmuch-draft-save-plaintext
 	((ask)
 	 (unless (yes-or-no-p "(Customize `notmuch-draft-save-plaintext' to avoid this warning)
 This message contains mml tags that suggest it is intended to be encrypted.
diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el
index ab6ee798..bdf584e6 100644
--- a/emacs/notmuch-hello.el
+++ b/emacs/notmuch-hello.el
@@ -21,7 +21,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
+
 (require 'widget)
 (require 'wid-edit) ; For `widget-forward'.
 
@@ -47,17 +48,19 @@ lists (NAME QUERY COUNT-QUERY)."
    ((keywordp (car saved-search))
     (plist-get saved-search field))
    ;; It is not a plist so it is an old-style entry.
-   ((consp (cdr saved-search)) ;; It is a list (NAME QUERY COUNT-QUERY)
-    (case field
-      (:name (first saved-search))
-      (:query (second saved-search))
-      (:count-query (third saved-search))
-      (t nil)))
-   (t  ;; It is a cons-cell (NAME . QUERY)
-    (case field
-      (:name (car saved-search))
-      (:query (cdr saved-search))
-      (t nil)))))
+   ((consp (cdr saved-search))
+    (pcase-let ((`(,name ,query ,count-query) saved-search))
+      (cl-case field
+	(:name name)
+	(:query query)
+	(:count-query count-query)
+	(t nil))))
+   (t
+    (pcase-let ((`(,name . ,query) saved-search))
+      (cl-case field
+	(:name name)
+	(:query query)
+	(t nil))))))
 
 (defun notmuch-hello-saved-search-to-plist (saved-search)
   "Return a copy of SAVED-SEARCH in plist form.
@@ -66,7 +69,7 @@ If saved search is a plist then just return a copy. In other
 cases, for backwards compatibility, convert to plist form and
 return that."
   (if (keywordp (car saved-search))
-      (copy-seq saved-search)
+      (copy-sequence saved-search)
     (let ((fields (list :name :query :count-query))
 	  plist-search)
       (dolist (field fields plist-search)
@@ -396,10 +399,10 @@ afterwards.")
 			       notmuch-saved-searches)))
     ;; If an existing saved search with this name exists, remove it.
     (setq notmuch-saved-searches
-	  (loop for elem in notmuch-saved-searches
-		if (not (equal name
-			       (notmuch-saved-search-get elem :name)))
-		collect elem))
+	  (cl-loop for elem in notmuch-saved-searches
+		   if (not (equal name
+				  (notmuch-saved-search-get elem :name)))
+		   collect elem))
     ;; Add the new one.
     (customize-save-variable 'notmuch-saved-searches
 			     (add-to-list 'notmuch-saved-searches
@@ -417,28 +420,28 @@ afterwards.")
     (notmuch-hello-update)))
 
 (defun notmuch-hello-longest-label (searches-alist)
-  (or (loop for elem in searches-alist
-	    maximize (length (notmuch-saved-search-get elem :name)))
+  (or (cl-loop for elem in searches-alist
+	       maximize (length (notmuch-saved-search-get elem :name)))
       0))
 
 (defun notmuch-hello-reflect-generate-row (ncols nrows row list)
   (let ((len (length list)))
-    (loop for col from 0 to (- ncols 1)
-	  collect (let ((offset (+ (* nrows col) row)))
-		    (if (< offset len)
-			(nth offset list)
-		      ;; Don't forget to insert an empty slot in the
-		      ;; output matrix if there is no corresponding
-		      ;; value in the input matrix.
-		      nil)))))
+    (cl-loop for col from 0 to (- ncols 1)
+	     collect (let ((offset (+ (* nrows col) row)))
+		       (if (< offset len)
+			   (nth offset list)
+			 ;; Don't forget to insert an empty slot in the
+			 ;; output matrix if there is no corresponding
+			 ;; value in the input matrix.
+			 nil)))))
 
 (defun notmuch-hello-reflect (list ncols)
   "Reflect a `ncols' wide matrix represented by `list' along the
 diagonal."
   ;; Not very lispy...
   (let ((nrows (ceiling (length list) ncols)))
-    (loop for row from 0 to (- nrows 1)
-	  append (notmuch-hello-reflect-generate-row ncols nrows row list))))
+    (cl-loop for row from 0 to (- nrows 1)
+	     append (notmuch-hello-reflect-generate-row ncols nrows row list))))
 
 (defun notmuch-hello-widget-search (widget &rest ignore)
   (cond
@@ -584,7 +587,7 @@ with `notmuch-hello-query-counts'."
 		  (widget-insert (make-string column-indent ? )))
 	      (let* ((name (plist-get elem :name))
 		     (query (plist-get elem :query))
-		     (oldest-first (case (plist-get elem :sort-order)
+		     (oldest-first (cl-case (plist-get elem :sort-order)
 				     (newest-first nil)
 				     (oldest-first t)
 				     (otherwise notmuch-search-oldest-first)))
@@ -812,48 +815,48 @@ Complete list of currently available key bindings:
 		   "clear")
     (widget-insert "\n\n")
     (let ((start (point)))
-      (loop for i from 1 to notmuch-hello-recent-searches-max
-	    for search in notmuch-search-history do
-	    (let ((widget-symbol (intern (format "notmuch-hello-search-%d" i))))
-	      (set widget-symbol
-		   (widget-create 'editable-field
-				  ;; Don't let the search boxes be
-				  ;; less than 8 characters wide.
-				  :size (max 8
-					     (- (window-width)
-						;; Leave some space
-						;; at the start and
-						;; end of the
-						;; boxes.
-						(* 2 notmuch-hello-indent)
-						;; 1 for the space
-						;; before the
-						;; `[save]' button. 6
-						;; for the `[save]'
-						;; button.
-						1 6
-						;; 1 for the space
-						;; before the `[del]'
-						;; button. 5 for the
-						;; `[del]' button.
-						1 5))
-				  :action (lambda (widget &rest ignore)
-					    (notmuch-hello-search (widget-value widget)))
-				  search))
-	      (widget-insert " ")
-	      (widget-create 'push-button
-			     :notify (lambda (widget &rest ignore)
-				       (notmuch-hello-add-saved-search widget))
-			     :notmuch-saved-search-widget widget-symbol
-			     "save")
-	      (widget-insert " ")
-	      (widget-create 'push-button
-			     :notify (lambda (widget &rest ignore)
-				       (when (y-or-n-p "Are you sure you want to delete this search? ")
-					 (notmuch-hello-delete-search-from-history widget)))
-			     :notmuch-saved-search-widget widget-symbol
-			     "del"))
-	    (widget-insert "\n"))
+      (cl-loop for i from 1 to notmuch-hello-recent-searches-max
+	       for search in notmuch-search-history do
+	       (let ((widget-symbol (intern (format "notmuch-hello-search-%d" i))))
+		 (set widget-symbol
+		      (widget-create 'editable-field
+				     ;; Don't let the search boxes be
+				     ;; less than 8 characters wide.
+				     :size (max 8
+						(- (window-width)
+						   ;; Leave some space
+						   ;; at the start and
+						   ;; end of the
+						   ;; boxes.
+						   (* 2 notmuch-hello-indent)
+						   ;; 1 for the space
+						   ;; before the
+						   ;; `[save]' button. 6
+						   ;; for the `[save]'
+						   ;; button.
+						   1 6
+						   ;; 1 for the space
+						   ;; before the `[del]'
+						   ;; button. 5 for the
+						   ;; `[del]' button.
+						   1 5))
+				     :action (lambda (widget &rest ignore)
+					       (notmuch-hello-search (widget-value widget)))
+				     search))
+		 (widget-insert " ")
+		 (widget-create 'push-button
+				:notify (lambda (widget &rest ignore)
+					  (notmuch-hello-add-saved-search widget))
+				:notmuch-saved-search-widget widget-symbol
+				"save")
+		 (widget-insert " ")
+		 (widget-create 'push-button
+				:notify (lambda (widget &rest ignore)
+					  (when (y-or-n-p "Are you sure you want to delete this search? ")
+					    (notmuch-hello-delete-search-from-history widget)))
+				:notmuch-saved-search-widget widget-symbol
+				"del"))
+	       (widget-insert "\n"))
       (indent-rigidly start (point) notmuch-hello-indent))
     nil))
 
diff --git a/emacs/notmuch-jump.el b/emacs/notmuch-jump.el
index 1cdf5b50..92a5a2cc 100644
--- a/emacs/notmuch-jump.el
+++ b/emacs/notmuch-jump.el
@@ -22,7 +22,9 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile
+  (require 'cl-lib)
+  (require 'pcase))
 
 (require 'notmuch-lib)
 (require 'notmuch-hello)
@@ -51,7 +53,7 @@ fast way to jump to a saved search from anywhere in Notmuch."
 	  (let ((name (plist-get saved-search :name))
 		(query (plist-get saved-search :query))
 		(oldest-first
-		 (case (plist-get saved-search :sort-order)
+		 (cl-case (plist-get saved-search :sort-order)
 		   (newest-first nil)
 		   (oldest-first t)
 		   (otherwise (default-value 'notmuch-search-oldest-first)))))
@@ -127,18 +129,16 @@ buffer."
 
   ;; Compute the maximum key description width
   (let ((key-width 1))
-    (dolist (entry action-map)
+    (pcase-dolist (`(,key ,desc) action-map)
       (setq key-width
 	    (max key-width
-		 (string-width (format-kbd-macro (first entry))))))
+		 (string-width (format-kbd-macro key)))))
     ;; Format each action
-    (mapcar (lambda (entry)
-	      (let ((key (format-kbd-macro (first entry)))
-		    (desc (second entry)))
-		(concat
-		 (propertize key 'face 'minibuffer-prompt)
-		 (make-string (- key-width (length key)) ? )
-		 " " desc)))
+    (mapcar (pcase-lambda (`(,key ,desc))
+	      (setq key (format-kbd-macro key))
+	      (concat (propertize key 'face 'minibuffer-prompt)
+		      (make-string (- key-width (length key)) ? )
+		      " " desc))
 	    action-map)))
 
 (defun notmuch-jump--insert-items (width items)
@@ -173,28 +173,25 @@ buffer."
   "Translate ACTION-MAP into a minibuffer keymap."
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map notmuch-jump-minibuffer-map)
-    (dolist (action action-map)
-      (if (= (length (first action)) 1)
-	  (define-key map (first action)
+    (pcase-dolist (`(,key ,name ,fn) action-map)
+      (if (= (length key) 1)
+	  (define-key map key
 	    `(lambda () (interactive)
-	       (setq notmuch-jump--action ',(third action))
+	       (setq notmuch-jump--action ',fn)
 	       (exit-minibuffer)))))
     ;; By doing this in two passes (and checking if we already have a
     ;; binding) we avoid problems if the user specifies a binding which
     ;; is a prefix of another binding.
-    (dolist (action action-map)
-      (if (> (length (first action)) 1)
-	  (let* ((key (elt (first action) 0))
+    (pcase-dolist (`(,key ,name ,fn) action-map)
+      (if (> (length key) 1)
+	  (let* ((key (elt key 0))
 		 (keystr (string key))
 		 (new-prompt (concat prompt (format-kbd-macro keystr) " "))
 		 (action-submap nil))
 	    (unless (lookup-key map keystr)
-	      (dolist (act action-map)
-		(when (= key (elt (first act) 0))
-		  (push (list (substring (first act) 1)
-			      (second act)
-			      (third act))
-			action-submap)))
+	      (pcase-dolist (`(,k ,n ,f) action-map)
+		(when (= key (elt k 0))
+		  (push (list (substring k 1) n f) action-submap)))
 	      ;; We deal with backspace specially
 	      (push (list (kbd "DEL")
 			  "Backup"
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index e085a06b..01862f44 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -23,10 +23,12 @@
 
 ;;; Code:
 
+(require 'cl-lib)
+
 (require 'mm-util)
 (require 'mm-view)
 (require 'mm-decode)
-(require 'cl)
+
 (require 'notmuch-compat)
 
 (unless (require 'notmuch-version nil t)
@@ -574,7 +576,7 @@ for this message, if present."
 (defun notmuch-parts-filter-by-type (parts type)
   "Given a list of message parts, return a list containing the ones matching
 the given type."
-  (remove-if-not
+  (cl-remove-if-not
    (lambda (part) (notmuch-match-content-type (plist-get part :content-type) type))
    parts))
 
@@ -685,8 +687,8 @@ current buffer, if possible."
 ;; have symbols of the form :Header as keys, and the resulting alist will have
 ;; symbols of the form 'Header as keys.
 (defun notmuch-headers-plist-to-alist (plist)
-  (loop for (key value . rest) on plist by #'cddr
-	collect (cons (intern (substring (symbol-name key) 1)) value)))
+  (cl-loop for (key value . rest) on plist by #'cddr
+	   collect (cons (intern (substring (symbol-name key) 1)) value)))
 
 (defun notmuch-face-ensure-list-form (face)
   "Return FACE in face list form.
@@ -780,7 +782,7 @@ arguments passed to the sentinel.  COMMAND and ERR, if provided,
 are passed to `notmuch-check-exit-status'.  If COMMAND is not
 provided, it is taken from `process-command'."
   (let ((exit-status
-	 (case (process-status proc)
+	 (cl-case (process-status proc)
 	   ((exit) (process-exit-status proc))
 	   ((signal) msg))))
     (when exit-status
@@ -848,7 +850,7 @@ for `call-process'.  ARGS is as described for
 
   (let (stdin-string)
     (while (keywordp (car args))
-      (case (car args)
+      (cl-case (car args)
 	(:stdin-string (setq stdin-string (cadr args)
 			     args (cddr args)))
 	(otherwise
@@ -1026,8 +1028,4 @@ region if the region is active, or both `point' otherwise."
 
 (provide 'notmuch-lib)
 
-;; Local Variables:
-;; byte-compile-warnings: (not cl-functions)
-;; End:
-
 ;;; notmuch-lib.el ends here
diff --git a/emacs/notmuch-maildir-fcc.el b/emacs/notmuch-maildir-fcc.el
index ae56bacd..b9cca543 100644
--- a/emacs/notmuch-maildir-fcc.el
+++ b/emacs/notmuch-maildir-fcc.el
@@ -22,7 +22,8 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
+
 (require 'message)
 
 (require 'notmuch-lib)
@@ -251,12 +252,12 @@ If CREATE is non-nil then create the folder if necessary."
        (let ((response (notmuch-read-char-choice
 			"Insert failed: (r)etry, (c)reate folder, (i)gnore, or (e)dit the header? "
 			'(?r ?c ?i ?e))))
-	 (case response
-	       (?r (notmuch-maildir-fcc-with-notmuch-insert fcc-header))
-	       (?c (notmuch-maildir-fcc-with-notmuch-insert fcc-header 't))
-	       (?i 't)
-	       (?e (notmuch-maildir-fcc-with-notmuch-insert
-		    (read-from-minibuffer "Fcc header: " fcc-header)))))))))
+	 (cl-case response
+	   (?r (notmuch-maildir-fcc-with-notmuch-insert fcc-header))
+	   (?c (notmuch-maildir-fcc-with-notmuch-insert fcc-header 't))
+	   (?i 't)
+	   (?e (notmuch-maildir-fcc-with-notmuch-insert
+		(read-from-minibuffer "Fcc header: " fcc-header)))))))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -335,16 +336,16 @@ if needed."
     (let* ((prompt (format "Fcc %s is not a maildir: (r)etry, (c)reate folder, (i)gnore, or  (e)dit the header? "
 			   fcc-header))
 	    (response (notmuch-read-char-choice prompt '(?r ?c ?i ?e))))
-	 (case response
-	       (?r (notmuch-maildir-fcc-file-fcc fcc-header))
-	       (?c (if (file-writable-p fcc-header)
-		       (notmuch-maildir-fcc-create-maildir fcc-header)
-		     (message "No permission to create %s." fcc-header)
-		     (sit-for 2))
-		   (notmuch-maildir-fcc-file-fcc fcc-header))
-	       (?i 't)
-	       (?e (notmuch-maildir-fcc-file-fcc
-		    (read-from-minibuffer "Fcc header: " fcc-header)))))))
+	 (cl-case response
+	   (?r (notmuch-maildir-fcc-file-fcc fcc-header))
+	   (?c (if (file-writable-p fcc-header)
+		   (notmuch-maildir-fcc-create-maildir fcc-header)
+		 (message "No permission to create %s." fcc-header)
+		 (sit-for 2))
+	       (notmuch-maildir-fcc-file-fcc fcc-header))
+	   (?i 't)
+	   (?e (notmuch-maildir-fcc-file-fcc
+		(read-from-minibuffer "Fcc header: " fcc-header)))))))
 
 (defun notmuch-maildir-fcc-write-buffer-to-maildir (destdir &optional mark-seen)
   "Writes the current buffer to maildir destdir. If mark-seen is
diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el
index 76572b87..40a1e6bc 100644
--- a/emacs/notmuch-mua.el
+++ b/emacs/notmuch-mua.el
@@ -21,6 +21,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
+
 (require 'message)
 (require 'mm-view)
 (require 'format-spec)
@@ -30,8 +32,6 @@
 (require 'notmuch-draft)
 (require 'notmuch-message)
 
-(eval-when-compile (require 'cl))
-
 (declare-function notmuch-show-insert-body "notmuch-show" (msg body depth))
 (declare-function notmuch-fcc-header-setup "notmuch-maildir-fcc" ())
 (declare-function notmuch-maildir-message-do-fcc "notmuch-maildir-fcc" ())
@@ -140,17 +140,18 @@ Typically this is added to `notmuch-mua-send-hook'."
 	   ;; Limit search from reaching other possible parts of the message
 	   (let ((search-limit (search-forward "\n<#" nil t)))
 	     (message-goto-body)
-	     (loop while (re-search-forward notmuch-mua-attachment-regexp search-limit t)
-		   ;; For every instance of the "attachment" string
-		   ;; found, examine the text properties. If the text
-		   ;; has either a `face' or `syntax-table' property
-		   ;; then it is quoted text and should *not* cause the
-		   ;; user to be asked about a missing attachment.
-		   if (let ((props (text-properties-at (match-beginning 0))))
-			(not (or (memq 'syntax-table props)
-				 (memq 'face props))))
-		   return t
-		   finally return nil)))
+	     (cl-loop while (re-search-forward notmuch-mua-attachment-regexp
+					       search-limit t)
+		      ;; For every instance of the "attachment" string
+		      ;; found, examine the text properties. If the text
+		      ;; has either a `face' or `syntax-table' property
+		      ;; then it is quoted text and should *not* cause the
+		      ;; user to be asked about a missing attachment.
+		      if (let ((props (text-properties-at (match-beginning 0))))
+			   (not (or (memq 'syntax-table props)
+				    (memq 'face props))))
+		      return t
+		      finally return nil)))
 	 ;; ...but doesn't have a part with a filename...
 	 (save-excursion
 	   (message-goto-body)
@@ -203,11 +204,11 @@ Typically this is added to `notmuch-mua-send-hook'."
 
 (defun notmuch-mua-reply-crypto (parts)
   "Add mml sign-encrypt flag if any part of original message is encrypted."
-  (loop for part in parts
-	if (notmuch-match-content-type (plist-get part :content-type) "multipart/encrypted")
-	  do (mml-secure-message-sign-encrypt)
-	else if (notmuch-match-content-type (plist-get part :content-type) "multipart/*")
-	  do (notmuch-mua-reply-crypto (plist-get part :content))))
+  (cl-loop for part in parts
+	   if (notmuch-match-content-type (plist-get part :content-type) "multipart/encrypted")
+	     do (mml-secure-message-sign-encrypt)
+	   else if (notmuch-match-content-type (plist-get part :content-type) "multipart/*")
+	     do (notmuch-mua-reply-crypto (plist-get part :content))))
 
 ;; There is a bug in emacs 23's message.el that results in a newline
 ;; not being inserted after the References header, so the next header
@@ -252,14 +253,14 @@ Typically this is added to `notmuch-mua-send-hook'."
 	;; We modify message-header-format-alist to get around a bug in message.el.
 	;; See the comment above on notmuch-mua-insert-references.
 	(let ((message-header-format-alist
-	       (loop for pair in message-header-format-alist
-		     if (eq (car pair) 'References)
-		     collect (cons 'References
-				   (apply-partially
-				    'notmuch-mua-insert-references
-				    (cdr pair)))
-		     else
-		     collect pair)))
+	       (cl-loop for pair in message-header-format-alist
+			if (eq (car pair) 'References)
+			collect (cons 'References
+				      (apply-partially
+				       'notmuch-mua-insert-references
+				       (cdr pair)))
+			else
+			collect pair)))
 	  (notmuch-mua-mail (plist-get reply-headers :To)
 			    (notmuch-sanitize (plist-get reply-headers :Subject))
 			    (notmuch-headers-plist-to-alist reply-headers)
@@ -309,10 +310,10 @@ Typically this is added to `notmuch-mua-send-hook'."
 		       ;; Don't indent multipart sub-parts.
 		       (notmuch-show-indent-multipart nil))
 		    ;; We don't want sigstatus buttons (an information leak and usually wrong anyway).
-		    (letf (((symbol-function 'notmuch-crypto-insert-sigstatus-button) #'ignore)
-			   ((symbol-function 'notmuch-crypto-insert-encstatus-button) #'ignore))
-			  (notmuch-show-insert-body original (plist-get original :body) 0)
-			  (buffer-substring-no-properties (point-min) (point-max))))))
+		    (cl-letf (((symbol-function 'notmuch-crypto-insert-sigstatus-button) #'ignore)
+			      ((symbol-function 'notmuch-crypto-insert-encstatus-button) #'ignore))
+		      (notmuch-show-insert-body original (plist-get original :body) 0)
+		      (buffer-substring-no-properties (point-min) (point-max))))))
 
 	(set-mark (point))
 	(goto-char start)
@@ -526,10 +527,9 @@ the From: address."
       ;; Create a buffer-local queue for tag changes triggered when sending the message
       (when notmuch-message-forwarded-tags
 	(setq-local notmuch-message-queued-tag-changes
-		    (loop for id in forward-queries
-			  collect
-			  (cons id
-				notmuch-message-forwarded-tags))))
+		    (cl-loop for id in forward-queries
+			     collect
+			     (cons id notmuch-message-forwarded-tags))))
 
       ;; `message-forward-make-body' shows the User-agent header.  Hide
       ;; it again.
@@ -609,10 +609,10 @@ unencrypted.  Really send? "))))
   (run-hooks 'notmuch-mua-send-hook)
   (when (and (notmuch-mua-check-no-misplaced-secure-tag)
 	     (notmuch-mua-check-secure-tag-has-newline))
-    (letf (((symbol-function 'message-do-fcc) #'notmuch-maildir-message-do-fcc))
-	  (if exit
-	      (message-send-and-exit arg)
-	    (message-send arg)))))
+    (cl-letf (((symbol-function 'message-do-fcc) #'notmuch-maildir-message-do-fcc))
+      (if exit
+	  (message-send-and-exit arg)
+	(message-send arg)))))
 
 (defun notmuch-mua-send-and-exit (&optional arg)
   (interactive "P")
diff --git a/emacs/notmuch-parser.el b/emacs/notmuch-parser.el
index bb0379c1..dc9fbe2f 100644
--- a/emacs/notmuch-parser.el
+++ b/emacs/notmuch-parser.el
@@ -21,7 +21,7 @@
 
 ;;; Code:
 
-(require 'cl)
+(eval-when-compile (require 'cl-lib))
 
 (defun notmuch-sexp-create-parser ()
   "Return a new streaming S-expression parser.
@@ -70,7 +70,7 @@ returns the value."
 	     ;; error to be consistent with all other code paths.
 	     (read (current-buffer))
 	   ;; Go up a level and return an end token
-	   (decf (notmuch-sexp--depth sp))
+	   (cl-decf (notmuch-sexp--depth sp))
 	   (forward-char)
 	   'end))
 	((= (char-after) ?\()
@@ -94,8 +94,8 @@ returns the value."
 				  (notmuch-sexp--partial-state sp)))
 		      ;; A complete value is available if we've
 		      ;; reached depth 0.
-		      (depth (first new-state)))
-		 (assert (>= depth 0))
+		      (depth (car new-state)))
+		 (cl-assert (>= depth 0))
 		 (if (= depth 0)
 		     ;; Reset partial parse state
 		     (setf (notmuch-sexp--partial-state sp) nil
@@ -139,7 +139,7 @@ beginning of a list, throw invalid-read-syntax."
   (cond ((eobp) 'retry)
 	((= (char-after) ?\()
 	 (forward-char)
-	 (incf (notmuch-sexp--depth sp))
+	 (cl-incf (notmuch-sexp--depth sp))
 	 t)
 	(t
 	 ;; Skip over the bad character like `read' does
@@ -181,7 +181,7 @@ move point in the input buffer."
     (set (make-local-variable 'notmuch-sexp--state) 'begin))
   (let (done)
     (while (not done)
-      (case notmuch-sexp--state
+      (cl-case notmuch-sexp--state
 	(begin
 	 ;; Enter the list
 	 (if (eq (notmuch-sexp-begin-list notmuch-sexp--parser) 'retry)
@@ -190,7 +190,7 @@ move point in the input buffer."
 	(result
 	 ;; Parse a result
 	 (let ((result (notmuch-sexp-read notmuch-sexp--parser)))
-	   (case result
+	   (cl-case result
 	     (retry (setq done t))
 	     (end   (setq notmuch-sexp--state 'end))
 	     (t     (with-current-buffer result-buffer
@@ -204,8 +204,4 @@ move point in the input buffer."
 
 (provide 'notmuch-parser)
 
-;; Local Variables:
-;; byte-compile-warnings: (not cl-functions)
-;; End:
-
 ;;; notmuch-parser.el ends here
diff --git a/emacs/notmuch-pkg.el.tmpl b/emacs/notmuch-pkg.el.tmpl
index 3eb0e04e..9d0999c1 100644
--- a/emacs/notmuch-pkg.el.tmpl
+++ b/emacs/notmuch-pkg.el.tmpl
@@ -3,4 +3,5 @@
   "notmuch"
   %VERSION%
   "Emacs based front-end (MUA) for notmuch"
-  '((emacs "24")))
+  '((emacs "24")
+    (cl-lib "0.6.1")))
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 079281c3..59931453 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -23,7 +23,10 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile
+  (require 'cl-lib)
+  (require 'pcase))
+
 (require 'mm-view)
 (require 'message)
 (require 'mm-decode)
@@ -429,17 +432,16 @@ parsing fails."
 	(setq p-name (replace-regexp-in-string "\\\\" "" p-name))
 
 	;; Outer single and double quotes, which might be nested.
-	(loop
-	 with start-of-loop
-	 do (setq start-of-loop p-name)
+	(cl-loop with start-of-loop
+		 do (setq start-of-loop p-name)
 
-	 when (string-match "^\"\\(.*\\)\"$" p-name)
-	 do (setq p-name (match-string 1 p-name))
+		 when (string-match "^\"\\(.*\\)\"$" p-name)
+		 do (setq p-name (match-string 1 p-name))
 
-	 when (string-match "^'\\(.*\\)'$" p-name)
-	 do (setq p-name (match-string 1 p-name))
+		 when (string-match "^'\\(.*\\)'$" p-name)
+		 do (setq p-name (match-string 1 p-name))
 
-	 until (string= start-of-loop p-name)))
+		 until (string= start-of-loop p-name)))
 
       ;; If the address is 'foo at bar.com <foo at bar.com>' then show just
       ;; 'foo at bar.com'.
@@ -573,13 +575,13 @@ message at DEPTH in the current thread."
   ;; Recurse on sub-parts
   (let ((ctype (notmuch-split-content-type
 		(downcase (plist-get part :content-type)))))
-    (cond ((equal (first ctype) "multipart")
+    (cond ((equal (car ctype) "multipart")
 	   (mapc (apply-partially #'notmuch-show--register-cids msg)
 		 (plist-get part :content)))
 	  ((equal ctype '("message" "rfc822"))
 	   (notmuch-show--register-cids
 	    msg
-	    (first (plist-get (first (plist-get part :content)) :body)))))))
+	    (car (plist-get (car (plist-get part :content)) :body)))))))
 
 (defun notmuch-show--get-cid-content (cid)
   "Return a list (CID-content content-type) or nil.
@@ -590,8 +592,8 @@ enclosing angle brackets, a cid: prefix, or URL encoding.  This
 will return nil if the CID is unknown or cannot be retrieved."
   (let ((descriptor (cdr (assoc cid notmuch-show--cids))))
     (when descriptor
-      (let* ((msg (first descriptor))
-	     (part (second descriptor))
+      (let* ((msg (car descriptor))
+	     (part (cadr descriptor))
 	     ;; Request caching for this content, as some messages
 	     ;; reference the same cid: part many times (hundreds!).
 	     (content (notmuch-get-bodypart-binary
@@ -616,8 +618,8 @@ will return nil if the CID is unknown or cannot be retrieved."
 	  (with-current-buffer w3m-current-buffer
 	    (notmuch-show--get-cid-content cid))))
     (when content-and-type
-      (insert (first content-and-type))
-      (second content-and-type))))
+      (insert (car content-and-type))
+      (cadr content-and-type))))
 
 ;; MIME part renderers
 
@@ -785,7 +787,7 @@ will return nil if the CID is unknown or cannot be retrieved."
       ;; is defined before it will be shadowed by the letf below. Otherwise the version
       ;; in enriched.el may be loaded a bit later and used instead (for the first time).
       (require 'enriched)
-      (letf (((symbol-function 'enriched-decode-display-prop)
+      (cl-letf (((symbol-function 'enriched-decode-display-prop)
 		 (lambda (start end &optional param) (list start end))))
 	(notmuch-show-insert-part-*/* msg part content-type nth depth button))))
 
@@ -843,7 +845,7 @@ will return nil if the CID is unknown or cannot be retrieved."
 	   ;; shr strips the "cid:" part of URL, but doesn't
 	   ;; URL-decode it (see RFC 2392).
 	   (let ((cid (url-unhex-string url)))
-	     (first (notmuch-show--get-cid-content cid))))))
+	     (car (notmuch-show--get-cid-content cid))))))
     (shr-insert-document dom)
     t))
 
@@ -873,15 +875,16 @@ will return nil if the CID is unknown or cannot be retrieved."
 
 (defun notmuch-show-insert-bodypart-internal (msg part content-type nth depth button)
   ;; Run the handlers until one of them succeeds.
-  (loop for handler in (notmuch-show-handlers-for content-type)
-	until (condition-case err
-		  (funcall handler msg part content-type nth depth button)
-		;; Specifying `debug' here lets the debugger run if
-		;; `debug-on-error' is non-nil.
-		((debug error)
-		 (insert "!!! Bodypart handler `" (prin1-to-string handler) "' threw an error:\n"
-			 "!!! " (error-message-string err) "\n")
-		 nil))))
+  (cl-loop for handler in (notmuch-show-handlers-for content-type)
+	   until (condition-case err
+		     (funcall handler msg part content-type nth depth button)
+		   ;; Specifying `debug' here lets the debugger run if
+		   ;; `debug-on-error' is non-nil.
+		   ((debug error)
+		    (insert "!!! Bodypart handler `" (prin1-to-string handler)
+			    "' threw an error:\n"
+			    "!!! " (error-message-string err) "\n")
+		    nil))))
 
 (defun notmuch-show-create-part-overlays (button beg end)
   "Add an overlay to the part between BEG and END"
@@ -907,13 +910,15 @@ will return nil if the CID is unknown or cannot be retrieved."
   ;; watch out for sticky specs of t, which means all properties are
   ;; front-sticky/rear-nonsticky.
   (notmuch-map-text-property beg end 'front-sticky
-			     (lambda (v) (if (listp v)
-					     (pushnew :notmuch-part v)
-					   v)))
+			     (lambda (v)
+			       (if (listp v)
+				   (cl-pushnew :notmuch-part v)
+				 v)))
   (notmuch-map-text-property beg end 'rear-nonsticky
-			     (lambda (v) (if (listp v)
-					     (pushnew :notmuch-part v)
-					   v))))
+			     (lambda (v)
+			       (if (listp v)
+				   (cl-pushnew :notmuch-part v)
+				 v))))
 
 (defun notmuch-show-lazy-part (part-args button)
   ;; Insert the lazy part after the button for the part. We would just
@@ -941,7 +946,7 @@ will return nil if the CID is unknown or cannot be retrieved."
 	(indent-rigidly part-beg part-end (* notmuch-show-indent-messages-width depth)))
       (goto-char part-end)
       (delete-char 1)
-      (notmuch-show-record-part-information (second part-args)
+      (notmuch-show-record-part-information (cadr part-args)
 					    (button-start button)
 					    part-end)
       ;; Create the overlay. If the lazy-part turned out to be empty/not
@@ -1037,7 +1042,7 @@ is t, hide the part initially and show the button."
   ;; Register all content IDs for this message.  According to RFC
   ;; 2392, content IDs are *global*, but it's okay if an MUA treats
   ;; them as only global within a message.
-  (notmuch-show--register-cids msg (first body))
+  (notmuch-show--register-cids msg (car body))
 
   (mapc (lambda (part) (notmuch-show-insert-bodypart msg part depth)) body))
 
@@ -1220,13 +1225,13 @@ buttons for a corresponding notmuch search."
 		      (url-unhex-string (match-string 0 mid-cid)))))
 	  (push (list (match-beginning 0) (match-end 0)
 		      (notmuch-id-to-query mid)) links)))
-      (dolist (link links)
+      (pcase-dolist (`(,beg ,end ,link) links)
 	;; Remove the overlay created by goto-address-mode
-	(remove-overlays (first link) (second link) 'goto-address t)
-	(make-text-button (first link) (second link)
+	(remove-overlays beg end 'goto-address t)
+	(make-text-button beg end
 			  :type 'notmuch-button-type
 			  'action `(lambda (arg)
-				     (notmuch-show ,(third link) current-prefix-arg))
+				     (notmuch-show ,link current-prefix-arg))
 			  'follow-link t
 			  'help-echo "Mouse-1, RET: search for this message"
 			  'face goto-address-mail-face)))))
@@ -1387,9 +1392,9 @@ This includes:
 (defun notmuch-show-goto-message (msg-id)
   "Go to message with msg-id."
   (goto-char (point-min))
-  (unless (loop if (string= msg-id (notmuch-show-get-message-id))
-		return t
-		until (not (notmuch-show-goto-message-next)))
+  (unless (cl-loop if (string= msg-id (notmuch-show-get-message-id))
+		   return t
+		   until (not (notmuch-show-goto-message-next)))
     (goto-char (point-min))
     (message "Message-id not found."))
   (notmuch-show-message-adjust))
@@ -1406,9 +1411,9 @@ This includes:
 
     ;; Open those that were open.
     (goto-char (point-min))
-    (loop do (notmuch-show-message-visible (notmuch-show-get-message-properties)
-					   (member (notmuch-show-get-message-id) open))
-	  until (not (notmuch-show-goto-message-next)))
+    (cl-loop do (notmuch-show-message-visible (notmuch-show-get-message-properties)
+					      (member (notmuch-show-get-message-id) open))
+	     until (not (notmuch-show-goto-message-next)))
 
     (dolist (win-msg-pair win-msg-alist)
       (with-selected-window (car win-msg-pair)
@@ -1620,8 +1625,8 @@ of the current message."
 effects."
   (save-excursion
     (goto-char (point-min))
-    (loop do (funcall function)
-	  while (notmuch-show-goto-message-next))))
+    (cl-loop do (funcall function)
+	     while (notmuch-show-goto-message-next))))
 
 ;; Functions relating to the visibility of messages and their
 ;; components.
@@ -2177,9 +2182,9 @@ argument, hide all of the messages."
   (interactive)
   (save-excursion
     (goto-char (point-min))
-    (loop do (notmuch-show-message-visible (notmuch-show-get-message-properties)
-					   (not current-prefix-arg))
-	  until (not (notmuch-show-goto-message-next))))
+    (cl-loop do (notmuch-show-message-visible (notmuch-show-get-message-properties)
+					      (not current-prefix-arg))
+	     until (not (notmuch-show-goto-message-next))))
   (force-window-update))
 
 (defun notmuch-show-next-button ()
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 0500927d..bc83e3de 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -24,8 +24,12 @@
 ;;; Code:
 ;;
 
-(require 'cl)
+(require 'cl-lib)
+(eval-when-compile
+  (require 'pcase))
+
 (require 'crm)
+
 (require 'notmuch-lib)
 
 (declare-function notmuch-search-tag "notmuch" tag-changes)
@@ -277,10 +281,10 @@ This can be used with `notmuch-tag-format-image-data'."
   (save-match-data
     ;; Don't use assoc-default since there's no way to distinguish a
     ;; missing key from a present key with a null cdr.
-    (assoc* tag format-alist
-	    :test (lambda (tag key)
-		    (and (eq (string-match key tag) 0)
-			 (= (match-end 0) (length tag)))))))
+    (cl-assoc tag format-alist
+	      :test (lambda (tag key)
+		      (and (eq (string-match key tag) 0)
+			   (= (match-end 0) (length tag)))))))
 
 (defun notmuch-tag--do-format (tag formatted-tag formats)
   "Apply a tag-formats entry to TAG."
@@ -315,7 +319,7 @@ changed (the normal case) are shown using formats from
 	 (formatted-tag (gethash (cons tag tag-state) notmuch-tag--format-cache 'missing)))
     (when (eq formatted-tag 'missing)
       (let ((base (notmuch-tag--get-formats tag notmuch-tag-formats))
-	    (over (case tag-state
+	    (over (cl-case tag-state
 		    (deleted (notmuch-tag--get-formats
 			      tag notmuch-tag-deleted-formats))
 		    (added (notmuch-tag--get-formats
@@ -436,7 +440,7 @@ from TAGS if present."
     (dolist (tag-change tag-changes)
       (let ((op (string-to-char tag-change))
 	    (tag (unless (string= tag-change "") (substring tag-change 1))))
-	(case op
+	(cl-case op
 	  (?+ (unless (member tag result-tags)
 		(push tag result-tags)))
 	  (?- (setq result-tags (delete tag result-tags)))
@@ -511,22 +515,21 @@ and vice versa."
   ;; REVERSE is specified.
   (interactive "P")
   (let (action-map)
-    (dolist (binding notmuch-tagging-keys)
-      (let* ((tag-function (case major-mode
+    (pcase-dolist (`(,key ,tag ,name) notmuch-tagging-keys)
+      (let* ((tag-function (cl-case major-mode
 			     (notmuch-search-mode #'notmuch-search-tag)
 			     (notmuch-show-mode #'notmuch-show-tag)
 			     (notmuch-tree-mode #'notmuch-tree-tag)))
-	     (key (first binding))
-	     (forward-tag-change (if (symbolp (second binding))
-				     (symbol-value (second binding))
-				   (second binding)))
+	     (tag (if (symbolp tag)
+		      (symbol-value tag)
+		    tag))
 	     (tag-change (if reverse
-			     (notmuch-tag-change-list forward-tag-change 't)
-			   forward-tag-change))
-	     (name (or (and (not (string= (third binding) ""))
-			    (third binding))
-		       (and (symbolp (second binding))
-			    (symbol-name (second binding)))))
+			     (notmuch-tag-change-list tag 't)
+			   tag))
+	     (name (or (and (not (string= name ""))
+			    name)
+		       (and (symbolp name)
+			    (symbol-name name))))
 	     (name-string (if name
 			      (if reverse (concat "Reverse " name)
 				name)
@@ -546,7 +549,3 @@ and vice versa."
 ;;
 
 (provide 'notmuch-tag)
-
-;; Local Variables:
-;; byte-compile-warnings: (not cl-functions)
-;; End:
diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
index e5c23de2..254664c4 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -24,6 +24,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
+
 (require 'mail-parse)
 
 (require 'notmuch-lib)
@@ -32,7 +34,6 @@
 (require 'notmuch-tag)
 (require 'notmuch-parser)
 
-(eval-when-compile (require 'cl))
 (declare-function notmuch-search "notmuch" (&optional query oldest-first target-thread target-line))
 (declare-function notmuch-call-notmuch-process "notmuch" (&rest args))
 (declare-function notmuch-read-query "notmuch" (prompt))
@@ -721,10 +722,10 @@ found or nil if not."
  and call FUNCTION for side effects."
   (save-excursion
     (notmuch-tree-thread-top)
-    (loop collect (funcall function)
-	  do (forward-line)
-	  while (and (notmuch-tree-get-message-properties)
-		     (not (notmuch-tree-get-prop :first))))))
+    (cl-loop collect (funcall function)
+	     do (forward-line)
+	     while (and (notmuch-tree-get-message-properties)
+			(not (notmuch-tree-get-prop :first))))))
 
 (defun notmuch-tree-get-messages-ids-thread-search ()
   "Return a search string for all message ids of messages in the current thread."
@@ -905,10 +906,11 @@ message together with all its descendents."
 (defun notmuch-tree-insert-thread (thread depth tree-status)
   "Insert the collection of sibling sub-threads THREAD at depth DEPTH in the current forest."
   (let ((n (length thread)))
-    (loop for tree in thread
-	  for count from 1 to n
-
-	  do (notmuch-tree-insert-tree tree depth tree-status (eq count 1) (eq count n)))))
+    (cl-loop for tree in thread
+	     for count from 1 to n
+	     do (notmuch-tree-insert-tree tree depth tree-status
+					  (eq count 1)
+					  (eq count n)))))
 
 (defun notmuch-tree-insert-forest-thread (forest-thread)
   "Insert a single complete thread."
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index f5f03244..a980c7a2 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -65,7 +65,8 @@
 ;;
 ;;; Code:
 
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
+
 (require 'mm-view)
 (require 'message)
 
@@ -132,7 +133,7 @@ there will be called at other points of notmuch execution."
               (or (equal (car disposition) "attachment")
                   (and (equal (car disposition) "inline")
                        (assq 'filename disposition)))
-              (incf count))))
+              (cl-incf count))))
      mm-handle)
     count))
 
@@ -429,14 +430,13 @@ character position of the beginning of each result that overlaps
 the region between points BEG and END.  As a special case, if (=
 BEG END), FN will be applied to the result containing point
 BEG."
-
-  (lexical-let ((pos (notmuch-search-result-beginning beg))
-		;; End must be a marker in case fn changes the
-		;; text.
-		(end (copy-marker end))
-		;; Make sure we examine at least one result, even if
-		;; (= beg end).
-		(first t))
+  (let ((pos (notmuch-search-result-beginning beg))
+	;; End must be a marker in case fn changes the
+	;; text.
+	(end (copy-marker end))
+	;; Make sure we examine at least one result, even if
+	;; (= beg end).
+	(first t))
     ;; We have to be careful if the region extends beyond the results.
     ;; In this case, pos could be null or there could be no result at
     ;; pos.
@@ -478,10 +478,10 @@ is nil, include both matched and unmatched messages. If there are
 no messages in the region then return nil."
   (let ((query-list nil) (all (not only-matched)))
     (dolist (queries (notmuch-search-properties-in-region :query beg end))
-      (when (first queries)
-	(push (first queries) query-list))
-      (when (and all (second queries))
-	(push (second queries) query-list)))
+      (when (car queries)
+	(push (car queries) query-list))
+      (when (and all (cadr queries))
+	(push (cadr queries) query-list)))
     (when query-list
       (concat "(" (mapconcat 'identity query-list ") or (") ")"))))
 
@@ -568,12 +568,11 @@ thread."
   "Prompt for tag changes for the current thread or region.
 
 Returns (TAG-CHANGES REGION-BEGIN REGION-END)."
-  (let* ((region (notmuch-interactive-region))
-	 (beg (first region)) (end (second region))
-	 (prompt (if (= beg end) "Tag thread" "Tag region")))
-    (cons (notmuch-read-tag-changes
-	   (notmuch-search-get-tags-region beg end) prompt initial-input)
-	  region)))
+  (pcase-let ((`(,beg ,end) (notmuch-interactive-region)))
+    (list (notmuch-read-tag-changes (notmuch-search-get-tags-region beg end)
+				    (if (= beg end) "Tag thread" "Tag region")
+				    initial-input)
+	  beg end)))
 
 (defun notmuch-search-tag (tag-changes &optional beg end only-matched)
   "Change tags for the currently selected thread or region.
@@ -891,12 +890,13 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
   (let* ((saved-search
 	  (let (longest
 		(longest-length 0))
-	    (loop for tuple in notmuch-saved-searches
-		  if (let ((quoted-query (regexp-quote (notmuch-saved-search-get tuple :query))))
-		       (and (string-match (concat "^" quoted-query) query)
-			    (> (length (match-string 0 query))
-			       longest-length)))
-		  do (setq longest tuple))
+	    (cl-loop for tuple in notmuch-saved-searches
+		     if (let ((quoted-query
+			       (regexp-quote (notmuch-saved-search-get tuple :query))))
+			  (and (string-match (concat "^" quoted-query) query)
+			       (> (length (match-string 0 query))
+				  longest-length)))
+		     do (setq longest tuple))
 	    longest))
 	 (saved-search-name (notmuch-saved-search-get saved-search :name))
 	 (saved-search-query (notmuch-saved-search-get saved-search :query)))
@@ -917,7 +917,7 @@ See `notmuch-tag' for information on the format of TAG-CHANGES."
   "Read a notmuch-query from the minibuffer with completion.
 
 PROMPT is the string to prompt with."
-  (lexical-let*
+  (let*
       ((all-tags
         (mapcar (lambda (tag) (notmuch-escape-boolean-term tag))
                 (process-lines notmuch-command "search" "--output=tags" "*")))
@@ -928,7 +928,7 @@ PROMPT is the string to prompt with."
 		 (mapcar (lambda (tag) (concat "is:" tag)) all-tags)
 		 (mapcar (lambda (mimetype) (concat "mimetype:" mimetype)) (mailcap-mime-types)))))
     (let ((keymap (copy-keymap minibuffer-local-map))
-	  (current-query (case major-mode
+	  (current-query (cl-case major-mode
 			   (notmuch-search-mode (notmuch-search-get-query))
 			   (notmuch-show-mode (notmuch-show-get-query))
 			   (notmuch-tree-mode (notmuch-tree-get-query))))
@@ -1114,9 +1114,9 @@ notmuch buffers exist, run `notmuch'."
       (bury-buffer))
 
     ;; Find the first notmuch buffer.
-    (setq first (loop for buffer in (buffer-list)
-		      if (notmuch-interesting-buffer buffer)
-		      return buffer))
+    (setq first (cl-loop for buffer in (buffer-list)
+			 if (notmuch-interesting-buffer buffer)
+			 return buffer))
 
     (if first
 	;; If the first one we found is any other than the starting
diff --git a/test/test-lib.el b/test/test-lib.el
index 9946010b..14082d3c 100644
--- a/test/test-lib.el
+++ b/test/test-lib.el
@@ -20,7 +20,7 @@
 ;;
 ;; Authors: Dmitry Kurochkin <dmitry.kurochkin at gmail.com>
 
-(require 'cl)	;; This code is generally used uncompiled.
+(require 'cl-lib)
 
 ;; `read-file-name' by default uses `completing-read' function to read
 ;; user input.  It does not respect `standard-input' variable which we
-- 
2.25.1




More information about the notmuch mailing list