unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Byte-compilation of custom themes
@ 2018-01-20 21:01 Basil L. Contovounesios
  2018-01-24 16:16 ` Stefan Monnier
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-01-20 21:01 UTC (permalink / raw)
  To: emacs-devel

This email is a follow-up to a question[1] I asked on the Emacs Stack
Exchange Q&A forum a couple of months ago, which received no answers in
the interim.

[1] https://emacs.stackexchange.com/q/36892/15748

I am wondering why custom themes are ordinarily left non-byte-compiled,
based on the following observations:

1. All built-in themes under etc/themes/ set the file variable
   no-byte-compile to t.

2. The function custom-available-themes in lisp/custom.el considers only
   *-theme.el and not *-theme.elc files under custom-theme-load-path.

3. The command load-theme in lisp/custom.el is able to load *-theme.elc
   files under custom-theme-load-path, but does so only if there is no
   corresponding source file in the same directory.

4. The manual nodes '(elisp) Custom Themes', '(emacs) Custom Themes' and
   '(emacs) Creating Custom Themes' make no mention of byte-compilation.

Is this "aversion" to byte-compilation of custom themes intentional?  If
so, what is the reasoning behind it?  Should the documentation be
extended to describe it?

If not, should the functions custom-available-themes and load-theme be
made made less picky about which file extensions they consider?  Should
the behaviour of the latter be likened more to the that of the load
function in src/lread.c?

FWIW, I have not noticed any issues when using my own byte-compiled
custom themes.  The only minor nuisance is having to keep the source
files separate from their translations and out of
custom-theme-load-path. 

Thanks,

-- 
Basil



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-01-20 21:01 Byte-compilation of custom themes Basil L. Contovounesios
@ 2018-01-24 16:16 ` Stefan Monnier
  2018-01-30 22:16   ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-01-24 16:16 UTC (permalink / raw)
  To: emacs-devel

> I am wondering why custom themes are ordinarily left non-byte-compiled,
> based on the following observations:

Good question.

> Is this "aversion" to byte-compilation of custom themes intentional?

I think it's due to the idea that users might download theme files from
random places without realizing that it contains arbitrary Lisp code
(contrary to normal Emacs packages where we consider that users should
know that it contains arbitrary Lisp code).  So we prompt users to
confirm that they think the theme file is safe, and users can't be
expected to assess the safety of a .elc file, so we insist on using the
.el file, which the user can inspect without nearly as much pain.


        Stefan




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-01-24 16:16 ` Stefan Monnier
@ 2018-01-30 22:16   ` Basil L. Contovounesios
  2018-01-31  2:26     ` Stefan Monnier
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-01-30 22:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 764 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Is this "aversion" to byte-compilation of custom themes intentional?
>
> I think it's due to the idea that users might download theme files from
> random places without realizing that it contains arbitrary Lisp code
> (contrary to normal Emacs packages where we consider that users should
> know that it contains arbitrary Lisp code).  So we prompt users to
> confirm that they think the theme file is safe, and users can't be
> expected to assess the safety of a .elc file, so we insist on using the
> .el file, which the user can inspect without nearly as much pain.

Ah, that makes sense.  Do you think it would be worthwhile clarifying
this in the manual?  Is there a clearer way of saying the following?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: foo.diff --]
[-- Type: text/x-diff, Size: 754 bytes --]

diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
index 6c7ca260ab..7fea507fd0 100644
--- a/doc/lispref/customize.texi
+++ b/doc/lispref/customize.texi
@@ -1432,7 +1432,9 @@ Custom Themes
 would be evaluated when loading the theme, but that is bad form.
 To protect against loading themes containing malicious code, Emacs
 displays the source file and asks for confirmation from the user
-before loading any non-built-in theme for the first time.
+before loading any non-built-in theme for the first time.  As
+such, themes are not ordinarily byte-compiled, and source files
+always take precedence when Emacs is looking for a theme to load.
 
   The following functions are useful for programmatically enabling and
 disabling themes:

[-- Attachment #3: Type: text/plain, Size: 254 bytes --]


Why are built-in themes not exempt to this safety net, though?
Diminishing returns?

Finally, would you care to post your helpful explanation as an answer to
my Stack Exchange question, or would you rather I paraphrased this
thread?

Thanks,

-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-01-30 22:16   ` Basil L. Contovounesios
@ 2018-01-31  2:26     ` Stefan Monnier
  2018-02-01  0:45       ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-01-31  2:26 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: emacs-devel

> diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
> index 6c7ca260ab..7fea507fd0 100644
> --- a/doc/lispref/customize.texi
> +++ b/doc/lispref/customize.texi
> @@ -1432,7 +1432,9 @@ Custom Themes
>  would be evaluated when loading the theme, but that is bad form.
>  To protect against loading themes containing malicious code, Emacs
>  displays the source file and asks for confirmation from the user
> -before loading any non-built-in theme for the first time.
> +before loading any non-built-in theme for the first time.  As
> +such, themes are not ordinarily byte-compiled, and source files
> +always take precedence when Emacs is looking for a theme to load.
>  
>    The following functions are useful for programmatically enabling and
>  disabling themes:

Sounds good to me.

> Why are built-in themes not exempt to this safety net, though?

They're not?  There is code which tries to exempt them, so if they're
not, it's a bug in that code.

> Finally, would you care to post your helpful explanation as an answer to
> my Stack Exchange question, or would you rather I paraphrased this
> thread?

Feel free to post my answer there,


        Stefan



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-01-31  2:26     ` Stefan Monnier
@ 2018-02-01  0:45       ` Basil L. Contovounesios
  2018-02-02 14:25         ` Stefan Monnier
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-02-01  0:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-Clarify-byte-compilation-of-Custom-Themes-in-Elisp-m.patch --]
[-- Type: text/x-diff, Size: 1270 bytes --]

From 49288975a810d1f2186f656cede92db93ee85c56 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 31 Jan 2018 23:23:49 +0000
Subject: [PATCH] Clarify byte-compilation of "Custom Themes" in Elisp manual

* doc/lispref/customize.texi (Custom Themes): Clarify status of
byte-compiled custom themes.  Suggested in
https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00824.html.
---
 doc/lispref/customize.texi | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
index 6c7ca260ab..7fea507fd0 100644
--- a/doc/lispref/customize.texi
+++ b/doc/lispref/customize.texi
@@ -1432,7 +1432,9 @@ Custom Themes
 would be evaluated when loading the theme, but that is bad form.
 To protect against loading themes containing malicious code, Emacs
 displays the source file and asks for confirmation from the user
-before loading any non-built-in theme for the first time.
+before loading any non-built-in theme for the first time.  As
+such, themes are not ordinarily byte-compiled, and source files
+always take precedence when Emacs is looking for a theme to load.
 
   The following functions are useful for programmatically enabling and
 disabling themes:
-- 
2.15.1


[-- Attachment #2: Type: text/plain, Size: 1747 bytes --]


Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
>> index 6c7ca260ab..7fea507fd0 100644
>> --- a/doc/lispref/customize.texi
>> +++ b/doc/lispref/customize.texi
>> @@ -1432,7 +1432,9 @@ Custom Themes
>>  would be evaluated when loading the theme, but that is bad form.
>>  To protect against loading themes containing malicious code, Emacs
>>  displays the source file and asks for confirmation from the user
>> -before loading any non-built-in theme for the first time.
>> +before loading any non-built-in theme for the first time.  As
>> +such, themes are not ordinarily byte-compiled, and source files
>> +always take precedence when Emacs is looking for a theme to load.
>>  
>>    The following functions are useful for programmatically enabling and
>>  disabling themes:
>
> Sounds good to me.

I attach a patch with this amendment.  If it is up to scratch, would
someone please push it?

>> Why are built-in themes not exempt to this safety net, though?
>
> They're not?  There is code which tries to exempt them, so if they're
> not, it's a bug in that code.

Sorry, I should have been clearer.  As documented, load-theme indeed
exempts built-in themes from the custom-theme-load-confirm check.  What
I meant to ask is why built-in themes are not byte-compiled in addition
to being considered safe.  Are there any arguments against doing this,
other than any performance gain being negligible?

>> Finally, would you care to post your helpful explanation as an answer to
>> my Stack Exchange question, or would you rather I paraphrased this
>> thread?
>
> Feel free to post my answer there,

Done: https://emacs.stackexchange.com/a/38510/15748.

Thanks,

-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-02-01  0:45       ` Basil L. Contovounesios
@ 2018-02-02 14:25         ` Stefan Monnier
  2018-05-10  2:49           ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-02-02 14:25 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: emacs-devel

> I attach a patch with this amendment.

Installed in the emacs-26 branch, thank you.

> What I meant to ask is why built-in themes are not byte-compiled in
> addition to being considered safe.  Are there any arguments against
> doing this, other than any performance gain being negligible?

I can't think of any technical reason, indeed (except that we'd then
have to special case this in the code so as to load the .elc file
instead of the .el file).


        Stefan



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-02-02 14:25         ` Stefan Monnier
@ 2018-05-10  2:49           ` Basil L. Contovounesios
  2018-05-10  2:54             ` Basil L. Contovounesios
  2018-05-11 14:02             ` Eli Zaretskii
  0 siblings, 2 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-05-10  2:49 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From bfab661fce5ab91a5f589172c4929371b776e59e Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From 76939a778e7364750caa41e48695cfca4026f094 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 1625 bytes --]

From abd12437c69afb72e206de2d0ea96d1326717909 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 2 May 2018 21:18:24 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

* lisp/custom.el: (custom-available-themes): Use directory-files
instead of potentially mis-expanding filenames.
---
 lisp/custom.el | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..b286f49ff9 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,17 +1299,15 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      (dolist (file (directory-files dir nil suffix))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
   (let (lpath)
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7586 bytes --]

From 3233727e7ac7346bdcae28100805490365752b83 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 3 May 2018 15:47:02 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 47 +++++++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b286f49ff9..b8004cfd74 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -621,8 +621,8 @@ custom-note-var-changed
 \f
 ;;; Custom Themes
 
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +715,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +744,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +776,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +941,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +989,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1086,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1209,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1387,9 +1390,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1401,7 +1404,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1467,7 +1470,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1508,7 +1511,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7112 bytes --]

From 9b7b979c430347466adc412050b5548c89d588c4 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 02:31:17 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 50 +++++++++++++++++++++++------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..760e531268 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -35,10 +35,10 @@ custom-new-theme-mode-map
     (set-keymap-parent map (make-composed-keymap widget-keymap
 						 special-mode-map))
     (suppress-keymap map)
-    (define-key map "\C-x\C-s" 'custom-theme-write)
-    (define-key map "q" 'Custom-buffer-done)
-    (define-key map "n" 'widget-forward)
-    (define-key map "p" 'widget-backward)
+    (define-key map "\C-x\C-s" #'custom-theme-write)
+    (define-key map "q" #'Custom-buffer-done)
+    (define-key map "n" #'widget-forward)
+    (define-key map "p" #'widget-backward)
     map)
   "Keymap for `custom-new-theme-mode'.")
 
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -540,10 +540,10 @@ custom-theme-choose-mode-map
     (set-keymap-parent map (make-composed-keymap widget-keymap
 						 special-mode-map))
     (suppress-keymap map)
-    (define-key map "\C-x\C-s" 'custom-theme-save)
-    (define-key map "n" 'widget-forward)
-    (define-key map "p" 'widget-backward)
-    (define-key map "?" 'custom-describe-theme)
+    (define-key map "\C-x\C-s" #'custom-theme-save)
+    (define-key map "n" #'widget-forward)
+    (define-key map "p" #'widget-backward)
+    (define-key map "?" #'custom-describe-theme)
     map)
   "Keymap for `custom-theme-choose-mode'.")
 
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0006-Various-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7949 bytes --]

From 04c7fc5441ff1ad95eb03b9892675cae0f98fa72 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 3 May 2018 15:49:35 +0100
Subject: [PATCH 6/8] Various custom.el simplifications

* lisp/custom.el (custom-load-symbol): Specify NOERROR argument when
loading instead of wrapping in condition-case.
(custom-quote): Duplicate macroexp-quote.
(customize-mark-to-save, customize-mark-as-set, disable-theme)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes):
Simplify logic.
---
 lisp/custom.el | 102 ++++++++++++++++++++++---------------------------
 1 file changed, 45 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b8004cfd74..ae917c0292 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -633,14 +633,10 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (require 'cus-load nil t)
+      (require 'cus-start nil t)
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (require load nil t))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -658,7 +654,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (load load t)))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -691,16 +687,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -721,12 +713,11 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (if (and standard
+             (equal value (ignore-errors
+                            (eval (car standard)))))
+        (put symbol 'saved-value nil)
+      (put symbol 'saved-value (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -750,9 +741,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1287,11 +1277,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1335,8 +1323,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1376,18 +1364,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1420,23 +1408,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0007-Various-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3934 bytes --]

From c468916fa18a5ada2f5ff7413f998747bc0b9dec Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Various cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 760e531268..dbb9d1af90 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0008-Minor-subr-x-tweaks.patch --]
[-- Type: text/x-diff, Size: 1193 bytes --]

From 3921f5f18b4dcbcccb4761fac1edd539ac6ecdb3 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 3 May 2018 16:12:56 +0100
Subject: [PATCH 8/8] Minor subr-x tweaks

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-remove-suffix): One less call to length.
---
 lisp/emacs-lisp/subr-x.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..2ae31f593c 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -250,7 +250,7 @@ string-remove-prefix
 (defsubst string-remove-suffix (suffix string)
   "Remove SUFFIX from STRING if present."
   (if (string-suffix-p suffix string)
-      (substring string 0 (- (length string) (length suffix)))
+      (substring string 0 (- (length suffix)))
     string))
 
 (provide 'subr-x)
-- 
2.17.0


[-- Attachment #9: Type: text/plain, Size: 1683 bytes --]


Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> What I meant to ask is why built-in themes are not byte-compiled in
>> addition to being considered safe.  Are there any arguments against
>> doing this, other than any performance gain being negligible?
>
> I can't think of any technical reason, indeed (except that we'd then
> have to special case this in the code so as to load the .elc file
> instead of the .el file).

I went ahead and modified load-theme to support loading byte-compiled
themes considered safe, but then I couldn't resist tweaking some of the
surrounding (in that it all lives under the lisp/ directory) code, so I
attach 8 patches.

The first makes load-theme call load instead of
insert-file-contents+eval-buffer in the non-interactive case of the
theme being considered safe.  This allows either .elc or .el themes to
be loaded with the same semantics as usual Elisp loading.

The second disables the file-local variable no-byte-compile in all the
built-in themes.  Would we want to go one step further and include theme
byte-compilation as part of the build?  Or does that entail too much
effort for little to no gain?

The third simplifies the function custom-available-themes and also fixes
a theoretical issue with its arbitrary expansion of wildcards in custom
theme filenames.

The fourth and fifth enable lexical-binding in custom.el and
cus-theme.el, respectively.

The last three try to make various logic simplifications in custom.el,
cus-theme.el, and subr-x.el, respectively.

I hope this isn't dumping too much in one go.  Please let me know how I
can improve these patches, should any of their suggestions be welcome.

Thanks,

-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-10  2:49           ` Basil L. Contovounesios
@ 2018-05-10  2:54             ` Basil L. Contovounesios
  2018-05-11 14:07               ` Eli Zaretskii
  2018-05-11 14:02             ` Eli Zaretskii
  1 sibling, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-05-10  2:54 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

"Basil L. Contovounesios" <contovob@tcd.ie> writes:

> I went ahead and modified load-theme to support loading byte-compiled
> themes considered safe, but then I couldn't resist tweaking some of the
> surrounding (in that it all lives under the lisp/ directory) code, so I
> attach 8 patches.

I forgot to ask in my previous email whether the duplicate
';;; Custom Themes' headings in custom.el are intentional, and if not
how they might be better shuffled around.

-- 
Basil



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-10  2:49           ` Basil L. Contovounesios
  2018-05-10  2:54             ` Basil L. Contovounesios
@ 2018-05-11 14:02             ` Eli Zaretskii
  2018-05-11 15:16               ` Basil L. Contovounesios
  1 sibling, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2018-05-11 14:02 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Date: Thu, 10 May 2018 03:49:35 +0100
> Cc: emacs-devel@gnu.org
> 
> diff --git a/lisp/custom.el b/lisp/custom.el
> index 1fed5dce53..b286f49ff9 100644
> --- a/lisp/custom.el
> +++ b/lisp/custom.el
> @@ -1299,17 +1299,15 @@ custom-available-themes
>  loaded, and no effort is made to check that the files contain
>  valid Custom themes.  For a list of loaded themes, check the
>  variable `custom-known-themes'."
> -  (let (sym themes)
> +  (let ((suffix "-theme\\.el\\'")
> +        themes)
>      (dolist (dir (custom-theme--load-path))
> -      (when (file-directory-p dir)
> -	(dolist (file (file-expand-wildcards
> -		       (expand-file-name "*-theme.el" dir) t))
> -	  (setq file (file-name-nondirectory file))
> -	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
> -	       (setq sym (intern (match-string 1 file)))
> -	       (custom-theme-name-valid-p sym)
> -	       (push sym themes)))))
> -    (nreverse (delete-dups themes))))
> +      (dolist (file (directory-files dir nil suffix))

The original code carefully verified that the members in
custom-theme--load-path are directories, whereas your proposal calls
directory-files on each member unconditionally, which will barf if a
file is not a directory.

> -    (define-key map "\C-x\C-s" 'custom-theme-write)
> -    (define-key map "q" 'Custom-buffer-done)
> -    (define-key map "n" 'widget-forward)
> -    (define-key map "p" 'widget-backward)
> +    (define-key map "\C-x\C-s" #'custom-theme-write)
> +    (define-key map "q" #'Custom-buffer-done)
> +    (define-key map "n" #'widget-forward)
> +    (define-key map "p" #'widget-backward)

Really?  Are we going to switch to #'foo even in key bindings?

> diff --git a/lisp/custom.el b/lisp/custom.el
> index b8004cfd74..ae917c0292 100644
> --- a/lisp/custom.el
> +++ b/lisp/custom.el
> @@ -633,14 +633,10 @@ custom-load-symbol
>      (let ((custom-load-recursion t))
>        ;; Load these files if not already done,
>        ;; to make sure we know all the dependencies of SYMBOL.
> -      (condition-case nil
> -	  (require 'cus-load)
> -	(error nil))
> -      (condition-case nil
> -	  (require 'cus-start)
> -	(error nil))
> +      (require 'cus-load nil t)
> +      (require 'cus-start nil t)
>        (dolist (load (get symbol 'custom-loads))
> -	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
> +        (cond ((symbolp load) (require load nil t))
>  	      ;; This is subsumed by the test below, but it's much faster.
>  	      ((assoc load load-history))
>  	      ;; This was just (assoc (locate-library load) load-history)
> @@ -658,7 +654,7 @@ custom-load-symbol
>  	      ;; We are still loading it when we call this,
>  	      ;; and it is not in load-history yet.
>  	      ((equal load "cus-edit"))
> -	      (t (condition-case nil (load load) (error nil))))))))
> +              (t (load load t)))))))

Why are we dropping the safety nets here?

Thanks.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-10  2:54             ` Basil L. Contovounesios
@ 2018-05-11 14:07               ` Eli Zaretskii
  0 siblings, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2018-05-11 14:07 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Date: Thu, 10 May 2018 03:54:27 +0100
> Cc: emacs-devel@gnu.org
> 
> I forgot to ask in my previous email whether the duplicate
> ';;; Custom Themes' headings in custom.el are intentional, and if not
> how they might be better shuffled around.

The first one is a pasto, and should be removed.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-11 14:02             ` Eli Zaretskii
@ 2018-05-11 15:16               ` Basil L. Contovounesios
  2018-05-11 16:03                 ` Stefan Monnier
  2018-05-11 17:32                 ` Eli Zaretskii
  0 siblings, 2 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-05-11 15:16 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3870 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Date: Thu, 10 May 2018 03:49:35 +0100
>> Cc: emacs-devel@gnu.org
>> 
>> diff --git a/lisp/custom.el b/lisp/custom.el
>> index 1fed5dce53..b286f49ff9 100644
>> --- a/lisp/custom.el
>> +++ b/lisp/custom.el
>> @@ -1299,17 +1299,15 @@ custom-available-themes
>>  loaded, and no effort is made to check that the files contain
>>  valid Custom themes.  For a list of loaded themes, check the
>>  variable `custom-known-themes'."
>> -  (let (sym themes)
>> +  (let ((suffix "-theme\\.el\\'")
>> +        themes)
>>      (dolist (dir (custom-theme--load-path))
>> -      (when (file-directory-p dir)
>> -	(dolist (file (file-expand-wildcards
>> -		       (expand-file-name "*-theme.el" dir) t))
>> -	  (setq file (file-name-nondirectory file))
>> -	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
>> -	       (setq sym (intern (match-string 1 file)))
>> -	       (custom-theme-name-valid-p sym)
>> -	       (push sym themes)))))
>> -    (nreverse (delete-dups themes))))
>> +      (dolist (file (directory-files dir nil suffix))
>
> The original code carefully verified that the members in
> custom-theme--load-path are directories, whereas your proposal calls
> directory-files on each member unconditionally, which will barf if a
> file is not a directory.

The function custom-theme--load-path already incorporates the
file-directory-p check, so it is technically redundant here.
Would you rather it be kept regardless?

>> -    (define-key map "\C-x\C-s" 'custom-theme-write)
>> -    (define-key map "q" 'Custom-buffer-done)
>> -    (define-key map "n" 'widget-forward)
>> -    (define-key map "p" 'widget-backward)
>> +    (define-key map "\C-x\C-s" #'custom-theme-write)
>> +    (define-key map "q" #'Custom-buffer-done)
>> +    (define-key map "n" #'widget-forward)
>> +    (define-key map "p" #'widget-backward)
>
> Really?  Are we going to switch to #'foo even in key bindings?

Though I personally prefer to consistently #'-quote function symbols in
my own code, both for the extra byte-compiler check and narrower
in-buffer completion, I have no strong opinion here; I was simply making
the change in a sweeping fashion, in line with what I had perceived as a
welcome style.  Out of curiosity, though, what makes key bindings
special w.r.t. quoting?

>> diff --git a/lisp/custom.el b/lisp/custom.el
>> index b8004cfd74..ae917c0292 100644
>> --- a/lisp/custom.el
>> +++ b/lisp/custom.el
>> @@ -633,14 +633,10 @@ custom-load-symbol
>>      (let ((custom-load-recursion t))
>>        ;; Load these files if not already done,
>>        ;; to make sure we know all the dependencies of SYMBOL.
>> -      (condition-case nil
>> -	  (require 'cus-load)
>> -	(error nil))
>> -      (condition-case nil
>> -	  (require 'cus-start)
>> -	(error nil))
>> +      (require 'cus-load nil t)
>> +      (require 'cus-start nil t)
>>        (dolist (load (get symbol 'custom-loads))
>> -	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
>> +        (cond ((symbolp load) (require load nil t))
>>  	      ;; This is subsumed by the test below, but it's much faster.
>>  	      ((assoc load load-history))
>>  	      ;; This was just (assoc (locate-library load) load-history)
>> @@ -658,7 +654,7 @@ custom-load-symbol
>>  	      ;; We are still loading it when we call this,
>>  	      ;; and it is not in load-history yet.
>>  	      ((equal load "cus-edit"))
>> -	      (t (condition-case nil (load load) (error nil))))))))
>> +              (t (load load t)))))))
>
> Why are we dropping the safety nets here?

Because it hadn't occurred to silly us that we might want to
additionally protect against evaluation errors.

I reattach the patches, updated for the last two points of feedback and
to remove the duplicate 'Custom Themes' heading.

Thanks,

-- 
Basil


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From 9fab63a6d4eb89fa0c0728fb93c13c7ee63524bc Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From 8cb0bbce4dc574fdf458f528a4c30e48c9291c38 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 1642 bytes --]

From e2e1dd4834536d439600ec0db3a4ec061408d821 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 2 May 2018 21:18:24 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in filenames.
---
 lisp/custom.el | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..b286f49ff9 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,17 +1299,15 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      (dolist (file (directory-files dir nil suffix))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
   (let (lpath)
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From 469db438763a31e49cf2d0ca2925a835954d910c Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b286f49ff9..aa201e3331 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +938,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +986,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1083,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1206,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1387,9 +1387,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1401,7 +1401,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1467,7 +1467,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1508,7 +1508,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From 53e0f80510a6a5d0923a8e60627f3a8ba3239c0f Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7932 bytes --]

From b67f5d3b2022ed7e4e5eb6085a62c218d142f244 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:46:39 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 104 ++++++++++++++++++++++---------------------------
 1 file changed, 47 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index aa201e3331..b3311a1783 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,11 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (if (and standard
+             (equal value (ignore-errors
+                            (eval (car standard)))))
+        (put symbol 'saved-value nil)
+      (put symbol 'saved-value (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +740,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1284,11 +1276,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1332,8 +1322,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1373,18 +1363,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1417,23 +1407,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From 3454df6cd6010358f2228a003d7d4adc0f3a704e Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-Minor-subr-x-tweaks.patch --]
[-- Type: text/x-diff, Size: 1193 bytes --]

From 8e329124b0c869f3ca841d8f6fc2c885cd7b9126 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 3 May 2018 16:12:56 +0100
Subject: [PATCH 8/8] Minor subr-x tweaks

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-remove-suffix): One less call to length.
---
 lisp/emacs-lisp/subr-x.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..2ae31f593c 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -250,7 +250,7 @@ string-remove-prefix
 (defsubst string-remove-suffix (suffix string)
   "Remove SUFFIX from STRING if present."
   (if (string-suffix-p suffix string)
-      (substring string 0 (- (length string) (length suffix)))
+      (substring string 0 (- (length suffix)))
     string))
 
 (provide 'subr-x)
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-11 15:16               ` Basil L. Contovounesios
@ 2018-05-11 16:03                 ` Stefan Monnier
  2018-05-11 20:03                   ` Basil L. Contovounesios
  2018-05-11 17:32                 ` Eli Zaretskii
  1 sibling, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-05-11 16:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

> Though I personally prefer to consistently #'-quote function symbols in
> my own code, both for the extra byte-compiler check and narrower
> in-buffer completion, I have no strong opinion here; I was simply making
> the change in a sweeping fashion, in line with what I had perceived as a
> welcome style.  Out of curiosity, though, what makes key bindings
> special w.r.t. quoting?

[ I'm probably responsible in large part for the recent popularity of
  the #' notation, so I figured I should chime in:  ]

While I generally prefer to use #' where applicable, I have resisted the
temptation to use it in keymaps because I have found it leads to
"spurious" warnings more often than in other contexts (and the impact
of an invalid binding is also less serious than a call to
a non-existing function).

Also, to me #'f means "the function bound to this symbol" whereas 'f
means "the symbol f", and in key-bindings I really want to use "the
symbol" rather than "the associated function" because `C-h m` gives poor
results when keys are bound to lambda expressions.  It's a rather
"philosophical" argument, tho.


        Stefan



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-11 15:16               ` Basil L. Contovounesios
  2018-05-11 16:03                 ` Stefan Monnier
@ 2018-05-11 17:32                 ` Eli Zaretskii
  2018-05-11 20:43                   ` Basil L. Contovounesios
  1 sibling, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2018-05-11 17:32 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
> Date: Fri, 11 May 2018 16:16:09 +0100
> 
> > The original code carefully verified that the members in
> > custom-theme--load-path are directories, whereas your proposal calls
> > directory-files on each member unconditionally, which will barf if a
> > file is not a directory.
> 
> The function custom-theme--load-path already incorporates the
> file-directory-p check, so it is technically redundant here.
> Would you rather it be kept regardless?

We should at least have a comment there that we are relying on
custom-theme--load-path to do the test, and perhaps also an assertion.

> >> -    (define-key map "\C-x\C-s" 'custom-theme-write)
> >> -    (define-key map "q" 'Custom-buffer-done)
> >> -    (define-key map "n" 'widget-forward)
> >> -    (define-key map "p" 'widget-backward)
> >> +    (define-key map "\C-x\C-s" #'custom-theme-write)
> >> +    (define-key map "q" #'Custom-buffer-done)
> >> +    (define-key map "n" #'widget-forward)
> >> +    (define-key map "p" #'widget-backward)
> >
> > Really?  Are we going to switch to #'foo even in key bindings?
> 
> Though I personally prefer to consistently #'-quote function symbols in
> my own code, both for the extra byte-compiler check and narrower
> in-buffer completion, I have no strong opinion here; I was simply making
> the change in a sweeping fashion, in line with what I had perceived as a
> welcome style.  Out of curiosity, though, what makes key bindings
> special w.r.t. quoting?

Stefan gave one reason (with which I agree).  From POV, it's another
stab into my heart of a veteran reader of Emacs Lisp code.  I recently
find the code harder and harder to read due to all the new syntax and
unfamiliar functions.  You can ignore me on that, though.

Thanks.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-11 16:03                 ` Stefan Monnier
@ 2018-05-11 20:03                   ` Basil L. Contovounesios
  0 siblings, 0 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-05-11 20:03 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> While I generally prefer to use #' where applicable, I have resisted the
> temptation to use it in keymaps because I have found it leads to
> "spurious" warnings more often than in other contexts (and the impact
> of an invalid binding is also less serious than a call to
> a non-existing function).

Good point, thanks!

> Also, to me #'f means "the function bound to this symbol" whereas 'f
> means "the symbol f", and in key-bindings I really want to use "the
> symbol" rather than "the associated function" because `C-h m` gives poor
> results when keys are bound to lambda expressions.  It's a rather
> "philosophical" argument, tho.

Agreed; too bad I live for philosophical discourse. ;)

-- 
Basil



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-11 17:32                 ` Eli Zaretskii
@ 2018-05-11 20:43                   ` Basil L. Contovounesios
  2018-05-12  7:04                     ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-05-11 20:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1206 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
>> Date: Fri, 11 May 2018 16:16:09 +0100
>> 
>> > The original code carefully verified that the members in
>> > custom-theme--load-path are directories, whereas your proposal calls
>> > directory-files on each member unconditionally, which will barf if a
>> > file is not a directory.
>> 
>> The function custom-theme--load-path already incorporates the
>> file-directory-p check, so it is technically redundant here.
>> Would you rather it be kept regardless?
>
> We should at least have a comment there that we are relying on
> custom-theme--load-path to do the test, and perhaps also an assertion.

Do you mean a cl-assertion, or an emulation thereof?  E.g.:

(unless (file-directory-p dir)
  (signal 'file-missing
          (list "`custom-theme-load-path'" "No such directory" dir)))

(I'm unsure on the convention for file-missing errors.)

Either way, what is the benefit of barfing before directory-files does?
Wouldn't a docstring for custom-theme--load-path and a comment in
custom-available-themes suffice for the reader (they do for me)?  E.g.:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: custom.diff --]
[-- Type: text/x-diff, Size: 843 bytes --]

diff --git a/lisp/custom.el b/lisp/custom.el
index b3311a1783..d21e398646 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1292,6 +1292,7 @@ custom-available-themes
   (let ((suffix "-theme\\.el\\'")
         themes)
     (dolist (dir (custom-theme--load-path))
+      ;; `custom-theme--load-path' promises DIR exists.
       (dolist (file (directory-files dir nil suffix))
         (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
           (and (custom-theme-name-valid-p theme)
@@ -1300,6 +1301,8 @@ custom-available-themes
     (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into list of directories.
+Only existing directories are included in the path returned."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)

[-- Attachment #3: Type: text/plain, Size: 1517 bytes --]


>> >> -    (define-key map "\C-x\C-s" 'custom-theme-write)
>> >> -    (define-key map "q" 'Custom-buffer-done)
>> >> -    (define-key map "n" 'widget-forward)
>> >> -    (define-key map "p" 'widget-backward)
>> >> +    (define-key map "\C-x\C-s" #'custom-theme-write)
>> >> +    (define-key map "q" #'Custom-buffer-done)
>> >> +    (define-key map "n" #'widget-forward)
>> >> +    (define-key map "p" #'widget-backward)
>> >
>> > Really?  Are we going to switch to #'foo even in key bindings?
>> 
>> Though I personally prefer to consistently #'-quote function symbols in
>> my own code, both for the extra byte-compiler check and narrower
>> in-buffer completion, I have no strong opinion here; I was simply making
>> the change in a sweeping fashion, in line with what I had perceived as a
>> welcome style.  Out of curiosity, though, what makes key bindings
>> special w.r.t. quoting?
>
> Stefan gave one reason (with which I agree).  From POV, it's another
> stab into my heart of a veteran reader of Emacs Lisp code.  I recently
> find the code harder and harder to read due to all the new syntax and
> unfamiliar functions.  You can ignore me on that, though.

No, it's a respectable point and I appreciate it.  Besides, my original
intent was to change how themes are loaded, not how their libraries are
quoted; I simply got carried away, and I'm sure there's precedent on the
latter elsewhere.  Let me know whether any heart stabs remain in the
last patchset and I'll gladly revert them.

Thanks,

-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-11 20:43                   ` Basil L. Contovounesios
@ 2018-05-12  7:04                     ` Eli Zaretskii
  2018-06-01 20:48                       ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2018-05-12  7:04 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
> Date: Fri, 11 May 2018 21:43:42 +0100
> 
> > We should at least have a comment there that we are relying on
> > custom-theme--load-path to do the test, and perhaps also an assertion.
> 
> Do you mean a cl-assertion, or an emulation thereof?

I meant cl-assert.

> Either way, what is the benefit of barfing before directory-files does?

That you can control the text of the error message, and make it more
user-friendly.  Also, an assertion clearly means we intended this not
to happen, rather than that the code failed to handle some valid
situation.

Once again, the minimum I requested was a comment; it's up to you
whether to use cl-assert.  But see below.

> Wouldn't a docstring for custom-theme--load-path and a comment in
> custom-available-themes suffice for the reader (they do for me)?

We've seen many situations where code guidelines are violated, for
whatever reasons, so just documenting stuff is not enough.  Moreover,
custom-theme--load-path might some day change and invalidate our
assumption.  The way to prevent that from happening could be either
having the assertion in the caller, or by adding a test to the test
suite that makes sure the list returned by custom-theme--load-path
never includes anything but existing directories.

>      (dolist (dir (custom-theme--load-path))
> +      ;; `custom-theme--load-path' promises DIR exists.

"promises DIR exists and is a directory", I think.

>  (defun custom-theme--load-path ()
> +  "Expand `custom-theme-load-path' into list of directories.
> +Only existing directories are included in the path returned."

I'd find this text a bit of a riddle.  How about this instead:

    "Expand `custom-theme-load-path' into list of directories.
  Members of `custom-theme-load-path' that either don't exist or are not
  directories are omitted from the expansion."

Thanks.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-05-12  7:04                     ` Eli Zaretskii
@ 2018-06-01 20:48                       ` Basil L. Contovounesios
  2018-06-01 21:07                         ` Basil L. Contovounesios
  2018-06-02 11:24                         ` Eli Zaretskii
  0 siblings, 2 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-01 20:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3464 bytes --]

I realise this is low priority stuff, but I'm nonetheless sorry for
taking so long to respond.

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
>> Date: Fri, 11 May 2018 21:43:42 +0100
>> 
>> > We should at least have a comment there that we are relying on
>> > custom-theme--load-path to do the test, and perhaps also an assertion.
>> 
>> Do you mean a cl-assertion, or an emulation thereof?
>
> I meant cl-assert.

Unless I (being unfamiliar with the subtleties of the build and
bootstrap process) am missing something, I think it's too early to load
cl-lib here; at least 'make bootstrap' fails for me when I add
(eval-when-compile (require 'cl-lib)) to custom.el.  Is there a way
around this?  Is the (unless DIRP (signal 'file-missing ...)) spiel from
my last email a suitable alternative?  Would doing that be overkill?

>> Either way, what is the benefit of barfing before directory-files does?
>
> That you can control the text of the error message, and make it more
> user-friendly.  Also, an assertion clearly means we intended this not
> to happen, rather than that the code failed to handle some valid
> situation.

Understood.  I've noticed, however, that many, if not most, uses of
cl-assert don't specify a custom error message.  For future reference,
is this acceptable practice, or would we rather see consistent use of
more informative messages?

> Once again, the minimum I requested was a comment; it's up to you
> whether to use cl-assert.  But see below.
>
>> Wouldn't a docstring for custom-theme--load-path and a comment in
>> custom-available-themes suffice for the reader (they do for me)?
>
> We've seen many situations where code guidelines are violated, for
> whatever reasons, so just documenting stuff is not enough.  Moreover,
> custom-theme--load-path might some day change and invalidate our
> assumption.  The way to prevent that from happening could be either
> having the assertion in the caller, or by adding a test to the test
> suite that makes sure the list returned by custom-theme--load-path
> never includes anything but existing directories.

A limitation (which does not apply in this case) of having the assertion
in the caller is that this doesn't necessarily cover future callers, and
even if it does, then there are multiple callers checking the same
thing.  Either way, I think adding a regression test is a good idea.

>>      (dolist (dir (custom-theme--load-path))
>> +      ;; `custom-theme--load-path' promises DIR exists.
>
> "promises DIR exists and is a directory", I think.

Right, I was being lazy and imprecise by relying on the name DIR to
convey its being a directory.

>>  (defun custom-theme--load-path ()
>> +  "Expand `custom-theme-load-path' into list of directories.
>> +Only existing directories are included in the path returned."
>
> I'd find this text a bit of a riddle.  How about this instead:
>
>     "Expand `custom-theme-load-path' into list of directories.
>   Members of `custom-theme-load-path' that either don't exist or are not
>   directories are omitted from the expansion."

SGTM, thanks.

I reattach the eight patches, updated for the feedback above.

The third patch has been updated to include the aforementioned
custom-theme-load-path documentation and tests.

The eighth patch now touches two more subr-x.el functions and adds tests
for its changes.

Thanks,

-- 
Basil


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From d4a711a775649c50e36e4bdc244c79f51ae7a7bc Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From f625cbdc4dbbcfa59a5773f193e4048bbb024191 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 6515 bytes --]

From 5368d8697d49ae8fb493031be22dee2dbe76624c Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 2 May 2018 21:18:24 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

For discussion, see thread starting at
https://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00222.html.
* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in filenames.
(custom-theme--load-path): Document return value.
* test/lisp/custom-tests.el: New file.
(custom-theme--load-path): New test.
---
 lisp/custom.el            | 22 +++++-----
 test/lisp/custom-tests.el | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+), 10 deletions(-)
 create mode 100644 test/lisp/custom-tests.el

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..157bb318e3 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,19 +1299,21 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      ;; `custom-theme--load-path' promises DIR exists and is a directory.
+      (dolist (file (directory-files dir nil suffix))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into a list of directories.
+Members of `custom-theme-load-path' that either don't exist or
+are not directories are omitted from the expansion."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 0000000000..96887f8f5f
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
+;;; custom-tests.el --- tests for custom.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest custom-theme--load-path ()
+  "Test `custom-theme--load-path' behavior."
+  (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
+    (unwind-protect
+        ;; Create all temporary files under the same deletable parent.
+        (let ((temporary-file-directory tmpdir))
+          ;; Path is empty.
+          (let ((custom-theme-load-path ()))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises non-existent file.
+          (let* ((name (make-temp-name tmpdir))
+                 (custom-theme-load-path (list name)))
+            (should (not (file-exists-p name)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing file.
+          (let* ((file (make-temp-file "file"))
+                 (custom-theme-load-path (list file)))
+            (should (file-exists-p file))
+            (should (not (file-directory-p file)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing directory.
+          (let* ((dir (make-temp-file "dir" t))
+                 (custom-theme-load-path (list dir)))
+            (should (file-directory-p dir))
+            (should (equal (custom-theme--load-path) custom-theme-load-path)))
+
+          ;; Expand `custom-theme-directory' path element.
+          (let ((custom-theme-load-path '(custom-theme-directory)))
+            (let ((custom-theme-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "file")))
+              (should (file-exists-p custom-theme-directory))
+              (should (not (file-directory-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "dir" t)))
+              (should (file-directory-p custom-theme-directory))
+              (should (equal (custom-theme--load-path)
+                             (list custom-theme-directory)))))
+
+          ;; Expand t path element.
+          (let ((custom-theme-load-path '(t)))
+            (let ((data-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p data-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((data-directory tmpdir)
+                  (themedir (expand-file-name "themes" tmpdir)))
+              (should (not (file-exists-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (with-temp-file themedir)
+              (should (file-exists-p themedir))
+              (should (not (file-directory-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (delete-file themedir)
+              (make-directory themedir)
+              (should (file-directory-p themedir))
+              (should (equal (custom-theme--load-path) (list themedir))))))
+      (when (file-directory-p tmpdir)
+        (delete-directory tmpdir t)))))
+
+;;; custom-tests.el ends here
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From bc839204dfa54de338f33f2814a144fd91ac20ef Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 157bb318e3..7ca71dd895 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +938,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +986,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1083,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1206,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1391,9 +1391,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1405,7 +1405,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1471,7 +1471,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1512,7 +1512,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From d850fa0df54be25d31b69273722754c3f27e28e5 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7892 bytes --]

From 531b5169240c4f7a39a3eabfec78154789d48fdc Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 31 May 2018 18:37:02 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 103 ++++++++++++++++++++++---------------------------
 1 file changed, 46 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 7ca71dd895..076790b661 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,10 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (put symbol 'saved-value
+         (unless (and standard
+                      (equal value (ignore-errors (eval (car standard)))))
+           (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +739,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1284,11 +1275,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1336,8 +1325,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1377,18 +1366,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1421,23 +1410,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From b3d9b63c36f30d6e1feb44d14c608551ccc8665f Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-Tweak-subr-x.el-substring-functions.patch --]
[-- Type: text/x-diff, Size: 5051 bytes --]

From a25af43b28e8a54d5f390c8c13c94609d5cb97e5 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 3 May 2018 16:12:56 +0100
Subject: [PATCH 8/8] Tweak subr-x.el substring functions

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-trim-left, string-trim-right, string-remove-suffix):
Make better use of substring for minor speedup.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-test-string-trim-left, subr-x-test-string-trim-right)
(subr-x-test-string-remove-prefix)
(subr-x-test-string-remove-suffix): New tests.
---
 lisp/emacs-lisp/subr-x.el            | 14 ++++-----
 test/lisp/emacs-lisp/subr-x-tests.el | 47 ++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..e89b5503a0 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -219,17 +219,17 @@ string-trim-left
   "Trim STRING of leading string matching REGEXP.
 
 REGEXP defaults to \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\`\\(?:" (or  regexp "[ \t\n\r]+")"\\)") string)
-      (replace-match "" t t string)
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
     string))
 
 (defsubst string-trim-right (string &optional regexp)
   "Trim STRING of trailing string matching REGEXP.
 
 REGEXP defaults to  \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
-      (replace-match "" t t string)
-    string))
+  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+                           string)))
+    (if i (substring string 0 i) string)))
 
 (defsubst string-trim (string &optional trim-left trim-right)
   "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.
@@ -250,7 +250,7 @@ string-remove-prefix
 (defsubst string-remove-suffix (suffix string)
   "Remove SUFFIX from STRING if present."
   (if (string-suffix-p suffix string)
-      (substring string 0 (- (length string) (length suffix)))
+      (substring string 0 (- (length suffix)))
     string))
 
 (provide 'subr-x)
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f..81467bab2d 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
                    (format "abs sum is: %s"))
                  "abs sum is: 15")))
 
+\f
+;; Substring tests
+
+(ert-deftest subr-x-test-string-trim-left ()
+  "Test `string-trim-left' behavior."
+  (should (equal (string-trim-left "") ""))
+  (should (equal (string-trim-left " \t\n\r") ""))
+  (should (equal (string-trim-left " \t\n\ra") "a"))
+  (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
+  (should (equal (string-trim-left "" "") ""))
+  (should (equal (string-trim-left "a" "") "a"))
+  (should (equal (string-trim-left "aa" "a*") ""))
+  (should (equal (string-trim-left "ba" "a*") "ba"))
+  (should (equal (string-trim-left "aa" "a*?") "aa"))
+  (should (equal (string-trim-left "aa" "a+?") "a")))
+
+(ert-deftest subr-x-test-string-trim-right ()
+  "Test `string-trim-right' behavior."
+  (should (equal (string-trim-right "") ""))
+  (should (equal (string-trim-right " \t\n\r") ""))
+  (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
+  (should (equal (string-trim-right "a \t\n\r") "a"))
+  (should (equal (string-trim-right "" "") ""))
+  (should (equal (string-trim-right "a" "") "a"))
+  (should (equal (string-trim-right "aa" "a*") ""))
+  (should (equal (string-trim-right "ab" "a*") "ab"))
+  (should (equal (string-trim-right "aa" "a*?") "")))
+
+(ert-deftest subr-x-test-string-remove-prefix ()
+  "Test `string-remove-prefix' behavior."
+  (should (equal (string-remove-prefix "" "") ""))
+  (should (equal (string-remove-prefix "" "a") "a"))
+  (should (equal (string-remove-prefix "a" "") ""))
+  (should (equal (string-remove-prefix "a" "b") "b"))
+  (should (equal (string-remove-prefix "a" "a") ""))
+  (should (equal (string-remove-prefix "a" "aa") "a"))
+  (should (equal (string-remove-prefix "a" "ab") "b")))
+
+(ert-deftest subr-x-test-string-remove-suffix ()
+  "Test `string-remove-suffix' behavior."
+  (should (equal (string-remove-suffix "" "") ""))
+  (should (equal (string-remove-suffix "" "a") "a"))
+  (should (equal (string-remove-suffix "a" "") ""))
+  (should (equal (string-remove-suffix "a" "b") "b"))
+  (should (equal (string-remove-suffix "a" "a") ""))
+  (should (equal (string-remove-suffix "a" "aa") "a"))
+  (should (equal (string-remove-suffix "a" "ba") "b")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-01 20:48                       ` Basil L. Contovounesios
@ 2018-06-01 21:07                         ` Basil L. Contovounesios
  2018-06-02 11:24                         ` Eli Zaretskii
  1 sibling, 0 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-01 21:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 599 bytes --]

"Basil L. Contovounesios" <contovob@tcd.ie> writes:

> @@ -250,7 +250,7 @@ string-remove-prefix
>  (defsubst string-remove-suffix (suffix string)
>    "Remove SUFFIX from STRING if present."
>    (if (string-suffix-p suffix string)
> -      (substring string 0 (- (length string) (length suffix)))
> +      (substring string 0 (- (length suffix)))
>      string))

Running the new subr-x-test-string-remove-suffix revealed that there is
a bug here when the length of SUFFIX is equal to zero.  I reattach the
patches with this "simplification" reverted.  Sorry about the hassle.

Thanks,

-- 
Basil


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From d4a711a775649c50e36e4bdc244c79f51ae7a7bc Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From f625cbdc4dbbcfa59a5773f193e4048bbb024191 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 6515 bytes --]

From 5368d8697d49ae8fb493031be22dee2dbe76624c Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 2 May 2018 21:18:24 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

For discussion, see thread starting at
https://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00222.html.
* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in filenames.
(custom-theme--load-path): Document return value.
* test/lisp/custom-tests.el: New file.
(custom-theme--load-path): New test.
---
 lisp/custom.el            | 22 +++++-----
 test/lisp/custom-tests.el | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+), 10 deletions(-)
 create mode 100644 test/lisp/custom-tests.el

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..157bb318e3 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,19 +1299,21 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      ;; `custom-theme--load-path' promises DIR exists and is a directory.
+      (dolist (file (directory-files dir nil suffix))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into a list of directories.
+Members of `custom-theme-load-path' that either don't exist or
+are not directories are omitted from the expansion."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 0000000000..96887f8f5f
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
+;;; custom-tests.el --- tests for custom.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest custom-theme--load-path ()
+  "Test `custom-theme--load-path' behavior."
+  (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
+    (unwind-protect
+        ;; Create all temporary files under the same deletable parent.
+        (let ((temporary-file-directory tmpdir))
+          ;; Path is empty.
+          (let ((custom-theme-load-path ()))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises non-existent file.
+          (let* ((name (make-temp-name tmpdir))
+                 (custom-theme-load-path (list name)))
+            (should (not (file-exists-p name)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing file.
+          (let* ((file (make-temp-file "file"))
+                 (custom-theme-load-path (list file)))
+            (should (file-exists-p file))
+            (should (not (file-directory-p file)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing directory.
+          (let* ((dir (make-temp-file "dir" t))
+                 (custom-theme-load-path (list dir)))
+            (should (file-directory-p dir))
+            (should (equal (custom-theme--load-path) custom-theme-load-path)))
+
+          ;; Expand `custom-theme-directory' path element.
+          (let ((custom-theme-load-path '(custom-theme-directory)))
+            (let ((custom-theme-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "file")))
+              (should (file-exists-p custom-theme-directory))
+              (should (not (file-directory-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "dir" t)))
+              (should (file-directory-p custom-theme-directory))
+              (should (equal (custom-theme--load-path)
+                             (list custom-theme-directory)))))
+
+          ;; Expand t path element.
+          (let ((custom-theme-load-path '(t)))
+            (let ((data-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p data-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((data-directory tmpdir)
+                  (themedir (expand-file-name "themes" tmpdir)))
+              (should (not (file-exists-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (with-temp-file themedir)
+              (should (file-exists-p themedir))
+              (should (not (file-directory-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (delete-file themedir)
+              (make-directory themedir)
+              (should (file-directory-p themedir))
+              (should (equal (custom-theme--load-path) (list themedir))))))
+      (when (file-directory-p tmpdir)
+        (delete-directory tmpdir t)))))
+
+;;; custom-tests.el ends here
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From bc839204dfa54de338f33f2814a144fd91ac20ef Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 157bb318e3..7ca71dd895 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +938,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +986,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1083,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1206,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1391,9 +1391,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1405,7 +1405,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1471,7 +1471,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1512,7 +1512,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From d850fa0df54be25d31b69273722754c3f27e28e5 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7892 bytes --]

From 531b5169240c4f7a39a3eabfec78154789d48fdc Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 31 May 2018 18:37:02 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 103 ++++++++++++++++++++++---------------------------
 1 file changed, 46 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 7ca71dd895..076790b661 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,10 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (put symbol 'saved-value
+         (unless (and standard
+                      (equal value (ignore-errors (eval (car standard)))))
+           (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +739,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1284,11 +1275,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1336,8 +1325,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1377,18 +1366,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1421,23 +1410,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From b3d9b63c36f30d6e1feb44d14c608551ccc8665f Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-Tweak-subr-x.el-substring-functions.patch --]
[-- Type: text/x-diff, Size: 4709 bytes --]

From 36e9ae0e7cfff1a466db085997a9e67d027e0a99 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 1 Jun 2018 21:58:10 +0100
Subject: [PATCH 8/8] Tweak subr-x.el substring functions

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-trim-left, string-trim-right):
Make better use of substring for minor speedup.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-test-string-trim-left, subr-x-test-string-trim-right)
(subr-x-test-string-remove-prefix)
(subr-x-test-string-remove-suffix): New tests.
---
 lisp/emacs-lisp/subr-x.el            | 12 +++----
 test/lisp/emacs-lisp/subr-x-tests.el | 47 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..eb3ec85ecc 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -219,17 +219,17 @@ string-trim-left
   "Trim STRING of leading string matching REGEXP.
 
 REGEXP defaults to \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\`\\(?:" (or  regexp "[ \t\n\r]+")"\\)") string)
-      (replace-match "" t t string)
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
     string))
 
 (defsubst string-trim-right (string &optional regexp)
   "Trim STRING of trailing string matching REGEXP.
 
 REGEXP defaults to  \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
-      (replace-match "" t t string)
-    string))
+  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+                           string)))
+    (if i (substring string 0 i) string)))
 
 (defsubst string-trim (string &optional trim-left trim-right)
   "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f..81467bab2d 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
                    (format "abs sum is: %s"))
                  "abs sum is: 15")))
 
+\f
+;; Substring tests
+
+(ert-deftest subr-x-test-string-trim-left ()
+  "Test `string-trim-left' behavior."
+  (should (equal (string-trim-left "") ""))
+  (should (equal (string-trim-left " \t\n\r") ""))
+  (should (equal (string-trim-left " \t\n\ra") "a"))
+  (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
+  (should (equal (string-trim-left "" "") ""))
+  (should (equal (string-trim-left "a" "") "a"))
+  (should (equal (string-trim-left "aa" "a*") ""))
+  (should (equal (string-trim-left "ba" "a*") "ba"))
+  (should (equal (string-trim-left "aa" "a*?") "aa"))
+  (should (equal (string-trim-left "aa" "a+?") "a")))
+
+(ert-deftest subr-x-test-string-trim-right ()
+  "Test `string-trim-right' behavior."
+  (should (equal (string-trim-right "") ""))
+  (should (equal (string-trim-right " \t\n\r") ""))
+  (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
+  (should (equal (string-trim-right "a \t\n\r") "a"))
+  (should (equal (string-trim-right "" "") ""))
+  (should (equal (string-trim-right "a" "") "a"))
+  (should (equal (string-trim-right "aa" "a*") ""))
+  (should (equal (string-trim-right "ab" "a*") "ab"))
+  (should (equal (string-trim-right "aa" "a*?") "")))
+
+(ert-deftest subr-x-test-string-remove-prefix ()
+  "Test `string-remove-prefix' behavior."
+  (should (equal (string-remove-prefix "" "") ""))
+  (should (equal (string-remove-prefix "" "a") "a"))
+  (should (equal (string-remove-prefix "a" "") ""))
+  (should (equal (string-remove-prefix "a" "b") "b"))
+  (should (equal (string-remove-prefix "a" "a") ""))
+  (should (equal (string-remove-prefix "a" "aa") "a"))
+  (should (equal (string-remove-prefix "a" "ab") "b")))
+
+(ert-deftest subr-x-test-string-remove-suffix ()
+  "Test `string-remove-suffix' behavior."
+  (should (equal (string-remove-suffix "" "") ""))
+  (should (equal (string-remove-suffix "" "a") "a"))
+  (should (equal (string-remove-suffix "a" "") ""))
+  (should (equal (string-remove-suffix "a" "b") "b"))
+  (should (equal (string-remove-suffix "a" "a") ""))
+  (should (equal (string-remove-suffix "a" "aa") "a"))
+  (should (equal (string-remove-suffix "a" "ba") "b")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
-- 
2.17.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-01 20:48                       ` Basil L. Contovounesios
  2018-06-01 21:07                         ` Basil L. Contovounesios
@ 2018-06-02 11:24                         ` Eli Zaretskii
  2018-06-02 18:53                           ` Basil L. Contovounesios
  1 sibling, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2018-06-02 11:24 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
> Date: Fri, 01 Jun 2018 21:48:21 +0100
> 
> >> Do you mean a cl-assertion, or an emulation thereof?
> >
> > I meant cl-assert.
> 
> Unless I (being unfamiliar with the subtleties of the build and
> bootstrap process) am missing something, I think it's too early to load
> cl-lib here; at least 'make bootstrap' fails for me when I add
> (eval-when-compile (require 'cl-lib)) to custom.el.  Is there a way
> around this?

Yes, explicitly check whether cl-lib is available, and skip the call
if not.  We don't need this assertion during the bootstrap.

> >> Either way, what is the benefit of barfing before directory-files does?
> >
> > That you can control the text of the error message, and make it more
> > user-friendly.  Also, an assertion clearly means we intended this not
> > to happen, rather than that the code failed to handle some valid
> > situation.
> 
> Understood.  I've noticed, however, that many, if not most, uses of
> cl-assert don't specify a custom error message.  For future reference,
> is this acceptable practice, or would we rather see consistent use of
> more informative messages?

My preference is clear from the above, but I don't have enough
experience to answer the rest of your question.

Thanks.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-02 11:24                         ` Eli Zaretskii
@ 2018-06-02 18:53                           ` Basil L. Contovounesios
  2018-06-02 19:32                             ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-02 18:53 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1018 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
>> Date: Fri, 01 Jun 2018 21:48:21 +0100
>> 
>> >> Do you mean a cl-assertion, or an emulation thereof?
>> >
>> > I meant cl-assert.
>> 
>> Unless I (being unfamiliar with the subtleties of the build and
>> bootstrap process) am missing something, I think it's too early to load
>> cl-lib here; at least 'make bootstrap' fails for me when I add
>> (eval-when-compile (require 'cl-lib)) to custom.el.  Is there a way
>> around this?
>
> Yes, explicitly check whether cl-lib is available, and skip the call
> if not.  We don't need this assertion during the bootstrap.

It somehow evaded me until now that cl-assert has an autoload cookie.
This means I can get away with calling it in custom-available-themes
without first requiring cl-lib, whether at top-level or inside the
function, right?  In other words, is the following kosher (and is the
wording up to scratch)?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: assert.diff --]
[-- Type: text/x-diff, Size: 655 bytes --]

diff --git a/lisp/custom.el b/lisp/custom.el
index 076790b661..f08a8e9c3e 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1291,7 +1291,9 @@ custom-available-themes
   (let ((suffix "-theme\\.el\\'")
         themes)
     (dolist (dir (custom-theme--load-path))
-      ;; `custom-theme--load-path' promises DIR exists and is a directory.
+      (cl-assert
+       (file-directory-p dir) t
+       "Non-existent directory in `custom-theme-load-path' expansion: %s")
       (dolist (file (directory-files dir nil suffix))
         (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
           (and (custom-theme-name-valid-p theme)

[-- Attachment #3: Type: text/plain, Size: 569 bytes --]


If not, WDYM exactly by "check whether cl-lib is available"?
Passing a non-nil NOERROR argument to a top-level

  (eval-when-compile (require 'cl-lib nil t))

still causes 'make bootstrap' to fail, and writing

  (when (require/featurep/fboundp ...)
    (cl-assert ...))

in custom-available-themes doesn't make sense to me, especially given
that cl-assert is autoloaded.

Am I misunderstanding something?  Sorry about my slow uptake on this;
I'm not deliberately trying to be obtuse, rather trying to learn what
the best approach is here and why.

Thanks,

-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-02 18:53                           ` Basil L. Contovounesios
@ 2018-06-02 19:32                             ` Eli Zaretskii
  2018-06-02 20:02                               ` Basil L. Contovounesios
  2018-06-03  3:52                               ` Stefan Monnier
  0 siblings, 2 replies; 33+ messages in thread
From: Eli Zaretskii @ 2018-06-02 19:32 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
> Date: Sat, 02 Jun 2018 19:53:09 +0100
> 
> It somehow evaded me until now that cl-assert has an autoload cookie.
> This means I can get away with calling it in custom-available-themes
> without first requiring cl-lib, whether at top-level or inside the
> function, right?  In other words, is the following kosher (and is the
> wording up to scratch)?

Yes, I think so.

> If not, WDYM exactly by "check whether cl-lib is available"?

I meant featurep, but since cl-assert is autoloaded, that shouldn't be
needed.



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-02 19:32                             ` Eli Zaretskii
@ 2018-06-02 20:02                               ` Basil L. Contovounesios
  2018-06-03  3:52                               ` Stefan Monnier
  1 sibling, 0 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-02 20:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 615 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Cc: <monnier@IRO.UMontreal.CA>,  <emacs-devel@gnu.org>
>> Date: Sat, 02 Jun 2018 19:53:09 +0100
>> 
>> It somehow evaded me until now that cl-assert has an autoload cookie.
>> This means I can get away with calling it in custom-available-themes
>> without first requiring cl-lib, whether at top-level or inside the
>> function, right?  In other words, is the following kosher (and is the
>> wording up to scratch)?
>
> Yes, I think so.

I reattach the patches with the third one updated accordingly.

Thanks,

-- 
Basil


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From d4a711a775649c50e36e4bdc244c79f51ae7a7bc Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From f625cbdc4dbbcfa59a5773f193e4048bbb024191 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 6569 bytes --]

From 094401d019cd2325e1d9089de19688aa18e7d813 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 2 May 2018 21:18:24 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

For discussion, see thread starting at
https://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00222.html.
* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in file names.
(custom-theme--load-path): Document return value.
* test/lisp/custom-tests.el: New file.
(custom-theme--load-path): New test.
---
 lisp/custom.el            | 24 ++++++-----
 test/lisp/custom-tests.el | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+), 10 deletions(-)
 create mode 100644 test/lisp/custom-tests.el

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..e076279485 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,19 +1299,23 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      (cl-assert
+       (file-directory-p dir) t
+       "Non-existent directory in `custom-theme-load-path' expansion: %s")
+      (dolist (file (directory-files dir nil suffix))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into a list of directories.
+Members of `custom-theme-load-path' that either don't exist or
+are not directories are omitted from the expansion."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 0000000000..96887f8f5f
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
+;;; custom-tests.el --- tests for custom.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest custom-theme--load-path ()
+  "Test `custom-theme--load-path' behavior."
+  (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
+    (unwind-protect
+        ;; Create all temporary files under the same deletable parent.
+        (let ((temporary-file-directory tmpdir))
+          ;; Path is empty.
+          (let ((custom-theme-load-path ()))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises non-existent file.
+          (let* ((name (make-temp-name tmpdir))
+                 (custom-theme-load-path (list name)))
+            (should (not (file-exists-p name)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing file.
+          (let* ((file (make-temp-file "file"))
+                 (custom-theme-load-path (list file)))
+            (should (file-exists-p file))
+            (should (not (file-directory-p file)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing directory.
+          (let* ((dir (make-temp-file "dir" t))
+                 (custom-theme-load-path (list dir)))
+            (should (file-directory-p dir))
+            (should (equal (custom-theme--load-path) custom-theme-load-path)))
+
+          ;; Expand `custom-theme-directory' path element.
+          (let ((custom-theme-load-path '(custom-theme-directory)))
+            (let ((custom-theme-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "file")))
+              (should (file-exists-p custom-theme-directory))
+              (should (not (file-directory-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "dir" t)))
+              (should (file-directory-p custom-theme-directory))
+              (should (equal (custom-theme--load-path)
+                             (list custom-theme-directory)))))
+
+          ;; Expand t path element.
+          (let ((custom-theme-load-path '(t)))
+            (let ((data-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p data-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((data-directory tmpdir)
+                  (themedir (expand-file-name "themes" tmpdir)))
+              (should (not (file-exists-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (with-temp-file themedir)
+              (should (file-exists-p themedir))
+              (should (not (file-directory-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (delete-file themedir)
+              (make-directory themedir)
+              (should (file-directory-p themedir))
+              (should (equal (custom-theme--load-path) (list themedir))))))
+      (when (file-directory-p tmpdir)
+        (delete-directory tmpdir t)))))
+
+;;; custom-tests.el ends here
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From 9cbf1b3f85d86e7660b9eeac8c65b29e404002ba Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index e076279485..88199a8da5 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +938,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +986,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1083,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1206,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1393,9 +1393,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1407,7 +1407,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1473,7 +1473,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1514,7 +1514,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From 00688ba60593f1d4e1c3810e0b560f1c3cbe1ac7 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7892 bytes --]

From 4df55309a51c4b8f7f421f4b080db9b64182ee34 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 31 May 2018 18:37:02 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 103 ++++++++++++++++++++++---------------------------
 1 file changed, 46 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 88199a8da5..f08a8e9c3e 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,10 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (put symbol 'saved-value
+         (unless (and standard
+                      (equal value (ignore-errors (eval (car standard)))))
+           (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +739,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1284,11 +1275,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1338,8 +1327,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1379,18 +1368,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1423,23 +1412,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From e37a3313a4e78161840d5009b65805ff7ba2a514 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-Tweak-subr-x.el-substring-functions.patch --]
[-- Type: text/x-diff, Size: 4709 bytes --]

From cf179936f1245f6f2b98385fd969abf78e8a15cf Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 1 Jun 2018 21:58:10 +0100
Subject: [PATCH 8/8] Tweak subr-x.el substring functions

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-trim-left, string-trim-right):
Make better use of substring for minor speedup.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-test-string-trim-left, subr-x-test-string-trim-right)
(subr-x-test-string-remove-prefix)
(subr-x-test-string-remove-suffix): New tests.
---
 lisp/emacs-lisp/subr-x.el            | 12 +++----
 test/lisp/emacs-lisp/subr-x-tests.el | 47 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..eb3ec85ecc 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -219,17 +219,17 @@ string-trim-left
   "Trim STRING of leading string matching REGEXP.
 
 REGEXP defaults to \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\`\\(?:" (or  regexp "[ \t\n\r]+")"\\)") string)
-      (replace-match "" t t string)
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
     string))
 
 (defsubst string-trim-right (string &optional regexp)
   "Trim STRING of trailing string matching REGEXP.
 
 REGEXP defaults to  \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
-      (replace-match "" t t string)
-    string))
+  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+                           string)))
+    (if i (substring string 0 i) string)))
 
 (defsubst string-trim (string &optional trim-left trim-right)
   "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f..81467bab2d 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
                    (format "abs sum is: %s"))
                  "abs sum is: 15")))
 
+\f
+;; Substring tests
+
+(ert-deftest subr-x-test-string-trim-left ()
+  "Test `string-trim-left' behavior."
+  (should (equal (string-trim-left "") ""))
+  (should (equal (string-trim-left " \t\n\r") ""))
+  (should (equal (string-trim-left " \t\n\ra") "a"))
+  (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
+  (should (equal (string-trim-left "" "") ""))
+  (should (equal (string-trim-left "a" "") "a"))
+  (should (equal (string-trim-left "aa" "a*") ""))
+  (should (equal (string-trim-left "ba" "a*") "ba"))
+  (should (equal (string-trim-left "aa" "a*?") "aa"))
+  (should (equal (string-trim-left "aa" "a+?") "a")))
+
+(ert-deftest subr-x-test-string-trim-right ()
+  "Test `string-trim-right' behavior."
+  (should (equal (string-trim-right "") ""))
+  (should (equal (string-trim-right " \t\n\r") ""))
+  (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
+  (should (equal (string-trim-right "a \t\n\r") "a"))
+  (should (equal (string-trim-right "" "") ""))
+  (should (equal (string-trim-right "a" "") "a"))
+  (should (equal (string-trim-right "aa" "a*") ""))
+  (should (equal (string-trim-right "ab" "a*") "ab"))
+  (should (equal (string-trim-right "aa" "a*?") "")))
+
+(ert-deftest subr-x-test-string-remove-prefix ()
+  "Test `string-remove-prefix' behavior."
+  (should (equal (string-remove-prefix "" "") ""))
+  (should (equal (string-remove-prefix "" "a") "a"))
+  (should (equal (string-remove-prefix "a" "") ""))
+  (should (equal (string-remove-prefix "a" "b") "b"))
+  (should (equal (string-remove-prefix "a" "a") ""))
+  (should (equal (string-remove-prefix "a" "aa") "a"))
+  (should (equal (string-remove-prefix "a" "ab") "b")))
+
+(ert-deftest subr-x-test-string-remove-suffix ()
+  "Test `string-remove-suffix' behavior."
+  (should (equal (string-remove-suffix "" "") ""))
+  (should (equal (string-remove-suffix "" "a") "a"))
+  (should (equal (string-remove-suffix "a" "") ""))
+  (should (equal (string-remove-suffix "a" "b") "b"))
+  (should (equal (string-remove-suffix "a" "a") ""))
+  (should (equal (string-remove-suffix "a" "aa") "a"))
+  (should (equal (string-remove-suffix "a" "ba") "b")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-02 19:32                             ` Eli Zaretskii
  2018-06-02 20:02                               ` Basil L. Contovounesios
@ 2018-06-03  3:52                               ` Stefan Monnier
  2018-06-03 11:21                                 ` Basil L. Contovounesios
  1 sibling, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-06-03  3:52 UTC (permalink / raw)
  To: emacs-devel

> I meant featurep, but since cl-assert is autoloaded, that shouldn't be

AFAICT it's not autoloaded.

I think the confusing comes from help-fns.el which does (require
'cl-lib), so if you do `C-h f cl-assert RET` it will indeed tell you
it's autoloaded, but it's just because `C-h f` ended up requiring
cl-lib.


        Stefan




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03  3:52                               ` Stefan Monnier
@ 2018-06-03 11:21                                 ` Basil L. Contovounesios
  2018-06-03 15:11                                   ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-03 11:21 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 926 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> I meant featurep, but since cl-assert is autoloaded, that shouldn't be
>
> AFAICT it's not autoloaded.

You're right, emacs -Q followed by (fboundp 'cl-assert) returns nil.

> I think the confusing comes from help-fns.el which does (require
> 'cl-lib), so if you do `C-h f cl-assert RET` it will indeed tell you
> it's autoloaded, but it's just because `C-h f` ended up requiring
> cl-lib.

No, the confusion comes from looking at the source of cl-macs.el, in
which cl-assert is given an ;;;###autoload cookie.  I see now that there
are some comments in cl-lib.el that suggest loading cl-loaddefs.el
involves some trickery, so I guess I don't get to eat the cake here.

In that case, I don't see how Eli's suggestion to predicate the
cl-assert call on (featurep 'cl-lib) will help, as feauturep is not
going to load the library for us.  Do we want the following instead?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: assert.diff --]
[-- Type: text/x-diff, Size: 857 bytes --]

diff --git a/lisp/custom.el b/lisp/custom.el
index 076790b661..e55c9db1ac 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1288,10 +1288,13 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
+  (eval-when-compile (require 'cl-lib))
   (let ((suffix "-theme\\.el\\'")
         themes)
     (dolist (dir (custom-theme--load-path))
-      ;; `custom-theme--load-path' promises DIR exists and is a directory.
+      (cl-assert
+       (file-directory-p dir) t
+       "Non-existent directory in `custom-theme-load-path' expansion: %s")
       (dolist (file (directory-files dir nil suffix))
         (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
           (and (custom-theme-name-valid-p theme)

[-- Attachment #3: Type: text/plain, Size: 11 bytes --]


-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03 11:21                                 ` Basil L. Contovounesios
@ 2018-06-03 15:11                                   ` Eli Zaretskii
  2018-06-03 16:08                                     ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2018-06-03 15:11 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Cc: <emacs-devel@gnu.org>, Eli Zaretskii <eliz@gnu.org>
> Date: Sun, 03 Jun 2018 12:21:07 +0100
> 
> You're right, emacs -Q followed by (fboundp 'cl-assert) returns nil.
> 
> > I think the confusing comes from help-fns.el which does (require
> > 'cl-lib), so if you do `C-h f cl-assert RET` it will indeed tell you
> > it's autoloaded, but it's just because `C-h f` ended up requiring
> > cl-lib.
> 
> No, the confusion comes from looking at the source of cl-macs.el, in
> which cl-assert is given an ;;;###autoload cookie.  I see now that there
> are some comments in cl-lib.el that suggest loading cl-loaddefs.el
> involves some trickery, so I guess I don't get to eat the cake here.
> 
> In that case, I don't see how Eli's suggestion to predicate the
> cl-assert call on (featurep 'cl-lib) will help, as feauturep is not
> going to load the library for us.

??? I meant the following obvious trick:

  (if (featurep 'cl-lib)
      (cl-assert ....))

Am I missing something?



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03 15:11                                   ` Eli Zaretskii
@ 2018-06-03 16:08                                     ` Basil L. Contovounesios
  2018-06-03 16:16                                       ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-03 16:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Cc: <emacs-devel@gnu.org>, Eli Zaretskii <eliz@gnu.org>
>> Date: Sun, 03 Jun 2018 12:21:07 +0100
>> 
>> You're right, emacs -Q followed by (fboundp 'cl-assert) returns nil.
>> 
>> > I think the confusing comes from help-fns.el which does (require
>> > 'cl-lib), so if you do `C-h f cl-assert RET` it will indeed tell you
>> > it's autoloaded, but it's just because `C-h f` ended up requiring
>> > cl-lib.
>> 
>> No, the confusion comes from looking at the source of cl-macs.el, in
>> which cl-assert is given an ;;;###autoload cookie.  I see now that there
>> are some comments in cl-lib.el that suggest loading cl-loaddefs.el
>> involves some trickery, so I guess I don't get to eat the cake here.
>> 
>> In that case, I don't see how Eli's suggestion to predicate the
>> cl-assert call on (featurep 'cl-lib) will help, as feauturep is not
>> going to load the library for us.
>
> ??? I meant the following obvious trick:
>
>   (if (featurep 'cl-lib)
>       (cl-assert ....))
>
> Am I missing something?

I understood what you meant, but not what this is supposed to do or
protect against.  You see, 'make bootstrap' fails not when there is an
ungaurded call to cl-assert in custom-available-themes, but when there
is a top-level (require 'cl-lib) in custom.el.

So, if we can't load cl-lib at the top-level of custom.el, and we don't
load cl-lib in custom-available-themes, then the featurep check says
"only call cl-assert if some other library has already loaded cl-lib for
us", which doesn't make sense to me.  What is the benefit of
conditionally calling an assertion at runtime?  Why wouldn't we want the
assertion to be exercised every time custom-available-themes is called?

Just to be clear, including any one of the following three top-level
forms in custom.el breaks 'make bootstrap', irrespective of the NOERROR
argument passed to require, and even when there is no subsequent mention
of cl-assert or any other cl-lib feature in custom.el:

(require 'cl-lib)
(eval-when-compile (require 'cl-lib))
(when t (require 'cl-lib))

In all three cases, 'make bootstrap' reports the following:

Loading custom (source)...
Warning: Unknown defun property ‘gv-setter’ in cl-fifth
Warning: Unknown defun property ‘gv-setter’ in cl-sixth
Warning: Unknown defun property ‘gv-setter’ in cl-seventh
Warning: Unknown defun property ‘gv-setter’ in cl-eighth
Warning: Unknown defun property ‘gv-setter’ in cl-ninth
Warning: Unknown defun property ‘gv-setter’ in cl-tenth
Symbol’s function definition is void: gv-define-simple-setter
Makefile:745: recipe for target 'bootstrap-emacs' failed

I hope I've clarified the source of my confusion and apologise if I'm
missing something obvious.

Thanks,

-- 
Basil



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03 16:08                                     ` Basil L. Contovounesios
@ 2018-06-03 16:16                                       ` Eli Zaretskii
  2018-06-03 17:48                                         ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2018-06-03 16:16 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: monnier, emacs-devel

> From: "Basil L. Contovounesios" <contovob@tcd.ie>
> Cc: <monnier@iro.umontreal.ca>,  <emacs-devel@gnu.org>
> Date: Sun, 03 Jun 2018 17:08:22 +0100
> 
> So, if we can't load cl-lib at the top-level of custom.el, and we don't
> load cl-lib in custom-available-themes, then the featurep check says
> "only call cl-assert if some other library has already loaded cl-lib for
> us", which doesn't make sense to me.  What is the benefit of
> conditionally calling an assertion at runtime?

In most sessions cl-lib is loaded pretty close to startup, so the
problem doesn't exist in practice, IMO.

> Why wouldn't we want the assertion to be exercised every time
> custom-available-themes is called?

Because it's complicated, and I don't see any reason to justify that
complication?

But this is not a string opinion, so we could just drop the issue and
move on.

Thanks.

> Just to be clear, including any one of the following three top-level
> forms in custom.el breaks 'make bootstrap', irrespective of the NOERROR
> argument passed to require, and even when there is no subsequent mention
> of cl-assert or any other cl-lib feature in custom.el:
> 
> (require 'cl-lib)
> (eval-when-compile (require 'cl-lib))
> (when t (require 'cl-lib))
> 
> In all three cases, 'make bootstrap' reports the following:
> 
> Loading custom (source)...
> Warning: Unknown defun property ‘gv-setter’ in cl-fifth
> Warning: Unknown defun property ‘gv-setter’ in cl-sixth
> Warning: Unknown defun property ‘gv-setter’ in cl-seventh
> Warning: Unknown defun property ‘gv-setter’ in cl-eighth
> Warning: Unknown defun property ‘gv-setter’ in cl-ninth
> Warning: Unknown defun property ‘gv-setter’ in cl-tenth
> Symbol’s function definition is void: gv-define-simple-setter
> Makefile:745: recipe for target 'bootstrap-emacs' failed

Any reason you require cl-lib and not cl-macs?



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03 16:16                                       ` Eli Zaretskii
@ 2018-06-03 17:48                                         ` Basil L. Contovounesios
  2018-06-03 20:22                                           ` Stefan Monnier
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-03 17:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2767 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

>> From: "Basil L. Contovounesios" <contovob@tcd.ie>
>> Cc: <monnier@iro.umontreal.ca>,  <emacs-devel@gnu.org>
>> Date: Sun, 03 Jun 2018 17:08:22 +0100
>> 
>> So, if we can't load cl-lib at the top-level of custom.el, and we don't
>> load cl-lib in custom-available-themes, then the featurep check says
>> "only call cl-assert if some other library has already loaded cl-lib for
>> us", which doesn't make sense to me.  What is the benefit of
>> conditionally calling an assertion at runtime?
>
> In most sessions cl-lib is loaded pretty close to startup, so the
> problem doesn't exist in practice, IMO.
>
>> Why wouldn't we want the assertion to be exercised every time
>> custom-available-themes is called?
>
> Because it's complicated, and I don't see any reason to justify that
> complication?
>
> But this is not a string opinion, so we could just drop the issue and
> move on.

Fair enough, though it's looking like the simplest solution is to keep
the original (when (file-directory-p dir) ...) check and avoid cl-lib
altogether.

Anyway, I have updated the relevant patch according to your suggestion
(the fboundp check is effectively equivalent to the featurep one, but
additionally silences the byte-compiler) and reattach the set of
patches; let me know if there are any outstanding issues with them.

>> Just to be clear, including any one of the following three top-level
>> forms in custom.el breaks 'make bootstrap', irrespective of the NOERROR
>> argument passed to require, and even when there is no subsequent mention
>> of cl-assert or any other cl-lib feature in custom.el:
>> 
>> (require 'cl-lib)
>> (eval-when-compile (require 'cl-lib))
>> (when t (require 'cl-lib))
>> 
>> In all three cases, 'make bootstrap' reports the following:
>> 
>> Loading custom (source)...
>> Warning: Unknown defun property ‘gv-setter’ in cl-fifth
>> Warning: Unknown defun property ‘gv-setter’ in cl-sixth
>> Warning: Unknown defun property ‘gv-setter’ in cl-seventh
>> Warning: Unknown defun property ‘gv-setter’ in cl-eighth
>> Warning: Unknown defun property ‘gv-setter’ in cl-ninth
>> Warning: Unknown defun property ‘gv-setter’ in cl-tenth
>> Symbol’s function definition is void: gv-define-simple-setter
>> Makefile:745: recipe for target 'bootstrap-emacs' failed
>
> Any reason you require cl-lib and not cl-macs?

I was following the suggestion of (info "(cl) Usage"), which implies
that the internal organisation of cl-lib is a bit of an implementation
detail.  I realise now that this suggestion is aimed more at external
packages, not Emacs core, though.  Bootstrap fails either way.

Thanks for indulging me,

-- 
Basil


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From ca42eaa51a0e3b2316b9783eb77cab316530c231 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From 6b509915240fabeeaa4a4aedbad87f146bd61f66 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 6683 bytes --]

From fe9bb45861c8f87cb62f69fb46d81286292352ab Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 2 May 2018 21:18:24 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

For discussion, see thread starting at
https://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00222.html.
* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in file names.
(custom-theme--load-path): Document return value.
* test/lisp/custom-tests.el: New file.
(custom-theme--load-path): New test.
---
 lisp/custom.el            | 26 +++++++-----
 test/lisp/custom-tests.el | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 10 deletions(-)
 create mode 100644 test/lisp/custom-tests.el

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..965c817e82 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,19 +1299,25 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      ;; Can't load `cl-lib' at top-level due to bootstrapping issues.
+      (when (fboundp 'cl-assert)
+        (cl-assert
+         (file-directory-p dir) t
+         "Non-existent directory in `custom-theme-load-path' expansion: %s"))
+      (dolist (file (directory-files dir nil suffix))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into a list of directories.
+Members of `custom-theme-load-path' that either don't exist or
+are not directories are omitted from the expansion."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 0000000000..96887f8f5f
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
+;;; custom-tests.el --- tests for custom.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest custom-theme--load-path ()
+  "Test `custom-theme--load-path' behavior."
+  (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
+    (unwind-protect
+        ;; Create all temporary files under the same deletable parent.
+        (let ((temporary-file-directory tmpdir))
+          ;; Path is empty.
+          (let ((custom-theme-load-path ()))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises non-existent file.
+          (let* ((name (make-temp-name tmpdir))
+                 (custom-theme-load-path (list name)))
+            (should (not (file-exists-p name)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing file.
+          (let* ((file (make-temp-file "file"))
+                 (custom-theme-load-path (list file)))
+            (should (file-exists-p file))
+            (should (not (file-directory-p file)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing directory.
+          (let* ((dir (make-temp-file "dir" t))
+                 (custom-theme-load-path (list dir)))
+            (should (file-directory-p dir))
+            (should (equal (custom-theme--load-path) custom-theme-load-path)))
+
+          ;; Expand `custom-theme-directory' path element.
+          (let ((custom-theme-load-path '(custom-theme-directory)))
+            (let ((custom-theme-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "file")))
+              (should (file-exists-p custom-theme-directory))
+              (should (not (file-directory-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "dir" t)))
+              (should (file-directory-p custom-theme-directory))
+              (should (equal (custom-theme--load-path)
+                             (list custom-theme-directory)))))
+
+          ;; Expand t path element.
+          (let ((custom-theme-load-path '(t)))
+            (let ((data-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p data-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((data-directory tmpdir)
+                  (themedir (expand-file-name "themes" tmpdir)))
+              (should (not (file-exists-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (with-temp-file themedir)
+              (should (file-exists-p themedir))
+              (should (not (file-directory-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (delete-file themedir)
+              (make-directory themedir)
+              (should (file-directory-p themedir))
+              (should (equal (custom-theme--load-path) (list themedir))))))
+      (when (file-directory-p tmpdir)
+        (delete-directory tmpdir t)))))
+
+;;; custom-tests.el ends here
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From f809fccdbd12aea44586b6b1c7b0102648c1351b Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 965c817e82..381636e4c2 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +938,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +986,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1083,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1206,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1395,9 +1395,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1409,7 +1409,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1475,7 +1475,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1516,7 +1516,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From d9881e411f2e8d10908d15f25733be189b66721f Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7892 bytes --]

From 537cfe5702d86eebcfc4909ed93fced71d218bf8 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 31 May 2018 18:37:02 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 103 ++++++++++++++++++++++---------------------------
 1 file changed, 46 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 381636e4c2..1233e44d05 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,10 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (put symbol 'saved-value
+         (unless (and standard
+                      (equal value (ignore-errors (eval (car standard)))))
+           (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +739,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1284,11 +1275,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1340,8 +1329,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1381,18 +1370,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1425,23 +1414,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From 41e2217167b4186467d75aff7faaeceb34813a5f Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-Tweak-subr-x.el-substring-functions.patch --]
[-- Type: text/x-diff, Size: 4709 bytes --]

From 460204efa19cadf5f7d89175125b24ab5fba0ccd Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 1 Jun 2018 21:58:10 +0100
Subject: [PATCH 8/8] Tweak subr-x.el substring functions

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-trim-left, string-trim-right):
Make better use of substring for minor speedup.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-test-string-trim-left, subr-x-test-string-trim-right)
(subr-x-test-string-remove-prefix)
(subr-x-test-string-remove-suffix): New tests.
---
 lisp/emacs-lisp/subr-x.el            | 12 +++----
 test/lisp/emacs-lisp/subr-x-tests.el | 47 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..eb3ec85ecc 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -219,17 +219,17 @@ string-trim-left
   "Trim STRING of leading string matching REGEXP.
 
 REGEXP defaults to \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\`\\(?:" (or  regexp "[ \t\n\r]+")"\\)") string)
-      (replace-match "" t t string)
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
     string))
 
 (defsubst string-trim-right (string &optional regexp)
   "Trim STRING of trailing string matching REGEXP.
 
 REGEXP defaults to  \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
-      (replace-match "" t t string)
-    string))
+  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+                           string)))
+    (if i (substring string 0 i) string)))
 
 (defsubst string-trim (string &optional trim-left trim-right)
   "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f..81467bab2d 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
                    (format "abs sum is: %s"))
                  "abs sum is: 15")))
 
+\f
+;; Substring tests
+
+(ert-deftest subr-x-test-string-trim-left ()
+  "Test `string-trim-left' behavior."
+  (should (equal (string-trim-left "") ""))
+  (should (equal (string-trim-left " \t\n\r") ""))
+  (should (equal (string-trim-left " \t\n\ra") "a"))
+  (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
+  (should (equal (string-trim-left "" "") ""))
+  (should (equal (string-trim-left "a" "") "a"))
+  (should (equal (string-trim-left "aa" "a*") ""))
+  (should (equal (string-trim-left "ba" "a*") "ba"))
+  (should (equal (string-trim-left "aa" "a*?") "aa"))
+  (should (equal (string-trim-left "aa" "a+?") "a")))
+
+(ert-deftest subr-x-test-string-trim-right ()
+  "Test `string-trim-right' behavior."
+  (should (equal (string-trim-right "") ""))
+  (should (equal (string-trim-right " \t\n\r") ""))
+  (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
+  (should (equal (string-trim-right "a \t\n\r") "a"))
+  (should (equal (string-trim-right "" "") ""))
+  (should (equal (string-trim-right "a" "") "a"))
+  (should (equal (string-trim-right "aa" "a*") ""))
+  (should (equal (string-trim-right "ab" "a*") "ab"))
+  (should (equal (string-trim-right "aa" "a*?") "")))
+
+(ert-deftest subr-x-test-string-remove-prefix ()
+  "Test `string-remove-prefix' behavior."
+  (should (equal (string-remove-prefix "" "") ""))
+  (should (equal (string-remove-prefix "" "a") "a"))
+  (should (equal (string-remove-prefix "a" "") ""))
+  (should (equal (string-remove-prefix "a" "b") "b"))
+  (should (equal (string-remove-prefix "a" "a") ""))
+  (should (equal (string-remove-prefix "a" "aa") "a"))
+  (should (equal (string-remove-prefix "a" "ab") "b")))
+
+(ert-deftest subr-x-test-string-remove-suffix ()
+  "Test `string-remove-suffix' behavior."
+  (should (equal (string-remove-suffix "" "") ""))
+  (should (equal (string-remove-suffix "" "a") "a"))
+  (should (equal (string-remove-suffix "a" "") ""))
+  (should (equal (string-remove-suffix "a" "b") "b"))
+  (should (equal (string-remove-suffix "a" "a") ""))
+  (should (equal (string-remove-suffix "a" "aa") "a"))
+  (should (equal (string-remove-suffix "a" "ba") "b")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03 17:48                                         ` Basil L. Contovounesios
@ 2018-06-03 20:22                                           ` Stefan Monnier
  2018-06-04  1:33                                             ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-06-03 20:22 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: Eli Zaretskii, emacs-devel

> Fair enough, though it's looking like the simplest solution is to keep
> the original (when (file-directory-p dir) ...) check and avoid cl-lib
> altogether.

Agreed, with a comment explaining that cl-lib macros can't be used at
this point for bootstrap reasons.


        Stefan



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-03 20:22                                           ` Stefan Monnier
@ 2018-06-04  1:33                                             ` Basil L. Contovounesios
  2018-07-03  7:57                                               ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-06-04  1:33 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 688 bytes --]

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> Fair enough, though it's looking like the simplest solution is to keep
>> the original (when (file-directory-p dir) ...) check and avoid cl-lib
>> altogether.
>
> Agreed, with a comment explaining that cl-lib macros can't be used at
> this point for bootstrap reasons.

How's the attached (see [PATCH 3/8])?  Too verbose?

P.S. I have been informed off-list by a fellow emacs-devel subscriber
     that multiple copies of some of my emails are being repeatedly
     delivered to them.  Has anyone else experienced this?  If so, any
     advice on how to fix this would be much appreciated.
     Sorry in advance.

Thanks,

-- 
Basil


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From 9efc72cc95531d47c4582bdf861b1a91800671e3 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index b7539685a8..1fed5dce53 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1221,43 +1221,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From b560ca9d2c94af2d4af5513ac6f9dffa7d51c1ae Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 6746 bytes --]

From 23f66699032a1e1c1bab496731cedfffaf71cc6d Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Mon, 4 Jun 2018 02:12:33 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

For discussion, see thread starting at
https://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00222.html.
* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in file names.
(custom-theme--load-path): Document return value.
* test/lisp/custom-tests.el: New file.
(custom-theme--load-path): New test.
---
 lisp/custom.el            | 26 +++++++-----
 test/lisp/custom-tests.el | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 10 deletions(-)
 create mode 100644 test/lisp/custom-tests.el

diff --git a/lisp/custom.el b/lisp/custom.el
index 1fed5dce53..ea58d8cbb7 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1299,19 +1299,25 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      ;; `custom-theme--load-path' promises DIR exists and is a
+      ;; directory, but `custom.el' is loaded too early during
+      ;; bootstrap to use `cl-lib' macros, so guard with
+      ;; `file-directory-p' instead of calling `cl-assert'.
+      (dolist (file (and (file-directory-p dir)
+                         (directory-files dir nil suffix)))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into a list of directories.
+Members of `custom-theme-load-path' that either don't exist or
+are not directories are omitted from the expansion."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 0000000000..96887f8f5f
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
+;;; custom-tests.el --- tests for custom.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest custom-theme--load-path ()
+  "Test `custom-theme--load-path' behavior."
+  (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
+    (unwind-protect
+        ;; Create all temporary files under the same deletable parent.
+        (let ((temporary-file-directory tmpdir))
+          ;; Path is empty.
+          (let ((custom-theme-load-path ()))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises non-existent file.
+          (let* ((name (make-temp-name tmpdir))
+                 (custom-theme-load-path (list name)))
+            (should (not (file-exists-p name)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing file.
+          (let* ((file (make-temp-file "file"))
+                 (custom-theme-load-path (list file)))
+            (should (file-exists-p file))
+            (should (not (file-directory-p file)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing directory.
+          (let* ((dir (make-temp-file "dir" t))
+                 (custom-theme-load-path (list dir)))
+            (should (file-directory-p dir))
+            (should (equal (custom-theme--load-path) custom-theme-load-path)))
+
+          ;; Expand `custom-theme-directory' path element.
+          (let ((custom-theme-load-path '(custom-theme-directory)))
+            (let ((custom-theme-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "file")))
+              (should (file-exists-p custom-theme-directory))
+              (should (not (file-directory-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "dir" t)))
+              (should (file-directory-p custom-theme-directory))
+              (should (equal (custom-theme--load-path)
+                             (list custom-theme-directory)))))
+
+          ;; Expand t path element.
+          (let ((custom-theme-load-path '(t)))
+            (let ((data-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p data-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((data-directory tmpdir)
+                  (themedir (expand-file-name "themes" tmpdir)))
+              (should (not (file-exists-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (with-temp-file themedir)
+              (should (file-exists-p themedir))
+              (should (not (file-directory-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (delete-file themedir)
+              (make-directory themedir)
+              (should (file-directory-p themedir))
+              (should (equal (custom-theme--load-path) (list themedir))))))
+      (when (file-directory-p tmpdir)
+        (delete-directory tmpdir t)))))
+
+;;; custom-tests.el ends here
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From 9ee1c5e2d734897298ebcd716cec4fad62d957ff Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index ea58d8cbb7..f60d6d217f 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -941,7 +938,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -989,8 +986,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1086,26 +1083,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1206,7 +1206,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1395,9 +1395,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1409,7 +1409,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1475,7 +1475,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1516,7 +1516,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From 1afe0d64386e80904459ba8fa2dc6ec2931f0e9e Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7892 bytes --]

From 48339577d2a4a4eee14fc2ae223fe3e59f93d239 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 31 May 2018 18:37:02 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 103 ++++++++++++++++++++++---------------------------
 1 file changed, 46 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index f60d6d217f..034d40eace 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,10 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (put symbol 'saved-value
+         (unless (and standard
+                      (equal value (ignore-errors (eval (car standard)))))
+           (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +739,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1284,11 +1275,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1340,8 +1329,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1381,18 +1370,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1425,23 +1414,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From ee62af507c85193266b656c5ac7811600eba2a10 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #9: 0008-Tweak-subr-x.el-substring-functions.patch --]
[-- Type: text/x-diff, Size: 4709 bytes --]

From 96b4a9219633f9b37d7f101b72b9475b4f3a20a7 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 1 Jun 2018 21:58:10 +0100
Subject: [PATCH 8/8] Tweak subr-x.el substring functions

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-trim-left, string-trim-right):
Make better use of substring for minor speedup.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-test-string-trim-left, subr-x-test-string-trim-right)
(subr-x-test-string-remove-prefix)
(subr-x-test-string-remove-suffix): New tests.
---
 lisp/emacs-lisp/subr-x.el            | 12 +++----
 test/lisp/emacs-lisp/subr-x-tests.el | 47 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 7fab9083e8..eb3ec85ecc 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -219,17 +219,17 @@ string-trim-left
   "Trim STRING of leading string matching REGEXP.
 
 REGEXP defaults to \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\`\\(?:" (or  regexp "[ \t\n\r]+")"\\)") string)
-      (replace-match "" t t string)
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
     string))
 
 (defsubst string-trim-right (string &optional regexp)
   "Trim STRING of trailing string matching REGEXP.
 
 REGEXP defaults to  \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
-      (replace-match "" t t string)
-    string))
+  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+                           string)))
+    (if i (substring string 0 i) string)))
 
 (defsubst string-trim (string &optional trim-left trim-right)
   "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f..81467bab2d 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
                    (format "abs sum is: %s"))
                  "abs sum is: 15")))
 
+\f
+;; Substring tests
+
+(ert-deftest subr-x-test-string-trim-left ()
+  "Test `string-trim-left' behavior."
+  (should (equal (string-trim-left "") ""))
+  (should (equal (string-trim-left " \t\n\r") ""))
+  (should (equal (string-trim-left " \t\n\ra") "a"))
+  (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
+  (should (equal (string-trim-left "" "") ""))
+  (should (equal (string-trim-left "a" "") "a"))
+  (should (equal (string-trim-left "aa" "a*") ""))
+  (should (equal (string-trim-left "ba" "a*") "ba"))
+  (should (equal (string-trim-left "aa" "a*?") "aa"))
+  (should (equal (string-trim-left "aa" "a+?") "a")))
+
+(ert-deftest subr-x-test-string-trim-right ()
+  "Test `string-trim-right' behavior."
+  (should (equal (string-trim-right "") ""))
+  (should (equal (string-trim-right " \t\n\r") ""))
+  (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
+  (should (equal (string-trim-right "a \t\n\r") "a"))
+  (should (equal (string-trim-right "" "") ""))
+  (should (equal (string-trim-right "a" "") "a"))
+  (should (equal (string-trim-right "aa" "a*") ""))
+  (should (equal (string-trim-right "ab" "a*") "ab"))
+  (should (equal (string-trim-right "aa" "a*?") "")))
+
+(ert-deftest subr-x-test-string-remove-prefix ()
+  "Test `string-remove-prefix' behavior."
+  (should (equal (string-remove-prefix "" "") ""))
+  (should (equal (string-remove-prefix "" "a") "a"))
+  (should (equal (string-remove-prefix "a" "") ""))
+  (should (equal (string-remove-prefix "a" "b") "b"))
+  (should (equal (string-remove-prefix "a" "a") ""))
+  (should (equal (string-remove-prefix "a" "aa") "a"))
+  (should (equal (string-remove-prefix "a" "ab") "b")))
+
+(ert-deftest subr-x-test-string-remove-suffix ()
+  "Test `string-remove-suffix' behavior."
+  (should (equal (string-remove-suffix "" "") ""))
+  (should (equal (string-remove-suffix "" "a") "a"))
+  (should (equal (string-remove-suffix "a" "") ""))
+  (should (equal (string-remove-suffix "a" "b") "b"))
+  (should (equal (string-remove-suffix "a" "a") ""))
+  (should (equal (string-remove-suffix "a" "aa") "a"))
+  (should (equal (string-remove-suffix "a" "ba") "b")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-06-04  1:33                                             ` Basil L. Contovounesios
@ 2018-07-03  7:57                                               ` Basil L. Contovounesios
  2018-07-11  1:40                                                 ` Stefan Monnier
  0 siblings, 1 reply; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-07-03  7:57 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Eli Zaretskii, emacs-devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: 0001-Improve-loading-of-byte-compiled-custom-themes.patch --]
[-- Type: text/x-diff, Size: 4290 bytes --]

From d3c87ab44e78c24c7f2e20f343e9df2a92cd3354 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:20:47 +0100
Subject: [PATCH 1/8] Improve loading of byte-compiled custom themes

* lisp/custom.el (load-theme):
Load byte-compiled file of safe themes when available.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 lisp/custom.el | 78 ++++++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 4a778a0573..b8ea8811a2 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1233,43 +1233,47 @@ load-theme
     (put theme 'theme-settings nil)
     (put theme 'theme-feature nil)
     (put theme 'theme-documentation nil))
-  (let ((fn (locate-file (concat (symbol-name theme) "-theme.el")
-			 (custom-theme--load-path)
-			 '("" "c"))))
-    (unless fn
-      (error "Unable to find theme file for `%s'" theme))
-    (with-temp-buffer
-      (insert-file-contents fn)
-      ;; Check file safety with `custom-safe-themes', prompting the
-      ;; user if necessary.
-      (when (or no-confirm
-		(eq custom-safe-themes t)
-		(and (memq 'default custom-safe-themes)
-		     (equal (file-name-directory fn)
-			    (expand-file-name "themes/" data-directory)))
-                (let ((hash (secure-hash 'sha256 (current-buffer))))
-                  (or (member hash custom-safe-themes)
-                      (custom-theme-load-confirm hash))))
-	(let ((custom--inhibit-theme-enable t)
-              (buffer-file-name fn))    ;For load-history.
-	  (eval-buffer))
-	;; Optimization: if the theme changes the `default' face, put that
-	;; entry first.  This avoids some `frame-set-background-mode' rigmarole
-	;; by assigning the new background immediately.
-	(let* ((settings (get theme 'theme-settings))
-	       (tail settings)
-	       found)
-	  (while (and tail (not found))
-	    (and (eq (nth 0 (car tail)) 'theme-face)
-		 (eq (nth 1 (car tail)) 'default)
-		 (setq found (car tail)))
-	    (setq tail (cdr tail)))
-	  (if found
-	      (put theme 'theme-settings (cons found (delq found settings)))))
-	;; Finally, enable the theme.
-	(unless no-enable
-	  (enable-theme theme))
-	t))))
+  (let ((file (locate-file (concat (symbol-name theme) "-theme.el")
+                           (custom-theme--load-path)
+                           '("" "c")))
+        (custom--inhibit-theme-enable t))
+    ;; Check file safety with `custom-safe-themes', prompting the
+    ;; user if necessary.
+    (cond ((not file)
+           (error "Unable to find theme file for `%s'" theme))
+          ((or no-confirm
+               (eq custom-safe-themes t)
+               (and (memq 'default custom-safe-themes)
+                    (equal (file-name-directory file)
+                           (expand-file-name "themes/" data-directory))))
+           ;; Theme is safe; load byte-compiled version if available.
+           (load (file-name-sans-extension file) nil t nil t))
+          ((with-temp-buffer
+             (insert-file-contents file)
+             (let ((hash (secure-hash 'sha256 (current-buffer))))
+               (when (or (member hash custom-safe-themes)
+                         (custom-theme-load-confirm hash))
+                 (eval-buffer nil nil file)
+                 t))))
+          (t
+           (error "Unable to load theme `%s'" theme))))
+  ;; Optimization: if the theme changes the `default' face, put that
+  ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
+  ;; by assigning the new background immediately.
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         found)
+    (while (and tail (not found))
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (eq (nth 1 (car tail)) 'default)
+           (setq found (car tail)))
+      (setq tail (cdr tail)))
+    (when found
+      (put theme 'theme-settings (cons found (delq found settings)))))
+  ;; Finally, enable the theme.
+  (unless no-enable
+    (enable-theme theme))
+  t)
 
 (defun custom-theme-load-confirm (hash)
   "Query the user about loading a Custom theme that may not be safe.
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-Disable-no-byte-compile-in-built-in-themes.patch --]
[-- Type: text/x-diff, Size: 6291 bytes --]

From 79d06b99e9aedd2bebaa2dff39157f50feacc474 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Wed, 9 May 2018 22:30:48 +0100
Subject: [PATCH 2/8] Disable no-byte-compile in built-in themes

* etc/themes/adwaita-theme.el:
* etc/themes/deeper-blue-theme.el:
* etc/themes/dichromacy-theme.el:
* etc/themes/leuven-theme.el:
* etc/themes/light-blue-theme.el:
* etc/themes/manoj-dark-theme.el:
* etc/themes/misterioso-theme.el:
* etc/themes/tango-dark-theme.el:
* etc/themes/tango-theme.el:
* etc/themes/tsdh-dark-theme.el:
* etc/themes/tsdh-light-theme.el:
* etc/themes/wheatgrass-theme.el:
* etc/themes/whiteboard-theme.el:
* etc/themes/wombat-theme.el: Disable no-byte-compile.

https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00614.html
https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00060.html
---
 etc/themes/adwaita-theme.el     | 4 ----
 etc/themes/deeper-blue-theme.el | 4 ----
 etc/themes/dichromacy-theme.el  | 4 ----
 etc/themes/leuven-theme.el      | 1 -
 etc/themes/light-blue-theme.el  | 4 ----
 etc/themes/manoj-dark-theme.el  | 4 ----
 etc/themes/misterioso-theme.el  | 4 ----
 etc/themes/tango-dark-theme.el  | 4 ----
 etc/themes/tango-theme.el       | 4 ----
 etc/themes/tsdh-dark-theme.el   | 4 ----
 etc/themes/tsdh-light-theme.el  | 5 -----
 etc/themes/wheatgrass-theme.el  | 4 ----
 etc/themes/whiteboard-theme.el  | 4 ----
 etc/themes/wombat-theme.el      | 4 ----
 14 files changed, 54 deletions(-)

diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index b376153510..415db8a191 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -99,8 +99,4 @@ adwaita
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; adwaita-theme.el  ends here
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index c6aa1751f4..0700f4f23d 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -110,8 +110,4 @@ deeper-blue
 
 (provide-theme 'deeper-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; deeper-blue-theme.el ends here
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 793209c055..bfced43aee 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -122,8 +122,4 @@ dichromacy
 
 (provide-theme 'dichromacy)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; dichromacy-theme.el ends here
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index 5c0d19ce81..c3c666588b 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -708,7 +708,6 @@ leuven
 ;; time-stamp-format: "%:y%02m%02d.%02H%02M"
 ;; time-stamp-start: "Version: "
 ;; time-stamp-end: "$"
-;; no-byte-compile: t
 ;; End:
 
 ;;; leuven-theme.el ends here
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 9935c565fb..ba00db6a49 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -61,8 +61,4 @@ light-blue
 
 (provide-theme 'light-blue)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; light-blue-theme.el ends here
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index fe61441d78..ddcaa0bd99 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -700,8 +700,4 @@ manoj-dark
 
 (provide-theme 'manoj-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; manoj-dark.el ends here
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index 42e448d28b..6c1eec0f42 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -103,8 +103,4 @@ misterioso
 
 (provide-theme 'misterioso)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; misterioso-theme.el  ends here
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 3b6eeb702e..dae77a5e62 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -170,8 +170,4 @@ tango-dark
 
 (provide-theme 'tango-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-dark-theme.el ends here
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index a7a79c04ad..4fe2480bc7 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -154,8 +154,4 @@ tango
 
 (provide-theme 'tango)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tango-theme.el ends here
diff --git a/etc/themes/tsdh-dark-theme.el b/etc/themes/tsdh-dark-theme.el
index 287fef8253..c216750cb2 100644
--- a/etc/themes/tsdh-dark-theme.el
+++ b/etc/themes/tsdh-dark-theme.el
@@ -144,8 +144,4 @@ tsdh-dark
 
 (provide-theme 'tsdh-dark)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-dark-theme.el ends here
diff --git a/etc/themes/tsdh-light-theme.el b/etc/themes/tsdh-light-theme.el
index 17a86fdbfe..ce9d1a2c3c 100644
--- a/etc/themes/tsdh-light-theme.el
+++ b/etc/themes/tsdh-light-theme.el
@@ -106,9 +106,4 @@ tsdh-light
 
 (provide-theme 'tsdh-light)
 
-
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; tsdh-light-theme.el ends here
diff --git a/etc/themes/wheatgrass-theme.el b/etc/themes/wheatgrass-theme.el
index 9585e3aa6e..8d34c28bf4 100644
--- a/etc/themes/wheatgrass-theme.el
+++ b/etc/themes/wheatgrass-theme.el
@@ -83,8 +83,4 @@ wheatgrass
 
 (provide-theme 'wheatgrass)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wheatgrass-theme.el ends here
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 5db0ddd68d..fe46cb0928 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -100,8 +100,4 @@ whiteboard
 
 (provide-theme 'whiteboard)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; whiteboard-theme.el ends here
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 583b8dc3f6..00f29bb9fa 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -102,8 +102,4 @@ wombat
 
 (provide-theme 'wombat)
 
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
-
 ;;; wombat-theme.el ends here
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0003-Fix-custom-available-themes-file-expansion.patch --]
[-- Type: text/x-diff, Size: 6746 bytes --]

From 6db2601d2082d949e44f15420a016e26f20745dd Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Mon, 4 Jun 2018 02:12:33 +0100
Subject: [PATCH 3/8] Fix custom-available-themes file expansion

For discussion, see thread starting at
https://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00222.html.
* lisp/custom.el: (custom-available-themes): Use directory-files
instead of performing arbitrary wildcard expansion in file names.
(custom-theme--load-path): Document return value.
* test/lisp/custom-tests.el: New file.
(custom-theme--load-path): New test.
---
 lisp/custom.el            | 26 +++++++-----
 test/lisp/custom-tests.el | 87 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 10 deletions(-)
 create mode 100644 test/lisp/custom-tests.el

diff --git a/lisp/custom.el b/lisp/custom.el
index b8ea8811a2..4536788eb2 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1311,19 +1311,25 @@ custom-available-themes
 loaded, and no effort is made to check that the files contain
 valid Custom themes.  For a list of loaded themes, check the
 variable `custom-known-themes'."
-  (let (sym themes)
+  (let ((suffix "-theme\\.el\\'")
+        themes)
     (dolist (dir (custom-theme--load-path))
-      (when (file-directory-p dir)
-	(dolist (file (file-expand-wildcards
-		       (expand-file-name "*-theme.el" dir) t))
-	  (setq file (file-name-nondirectory file))
-	  (and (string-match "\\`\\(.+\\)-theme.el\\'" file)
-	       (setq sym (intern (match-string 1 file)))
-	       (custom-theme-name-valid-p sym)
-	       (push sym themes)))))
-    (nreverse (delete-dups themes))))
+      ;; `custom-theme--load-path' promises DIR exists and is a
+      ;; directory, but `custom.el' is loaded too early during
+      ;; bootstrap to use `cl-lib' macros, so guard with
+      ;; `file-directory-p' instead of calling `cl-assert'.
+      (dolist (file (and (file-directory-p dir)
+                         (directory-files dir nil suffix)))
+        (let ((theme (intern (substring file 0 (string-match-p suffix file)))))
+          (and (custom-theme-name-valid-p theme)
+               (not (memq theme themes))
+               (push theme themes)))))
+    (nreverse themes)))
 
 (defun custom-theme--load-path ()
+  "Expand `custom-theme-load-path' into a list of directories.
+Members of `custom-theme-load-path' that either don't exist or
+are not directories are omitted from the expansion."
   (let (lpath)
     (dolist (f custom-theme-load-path)
       (cond ((eq f 'custom-theme-directory)
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
new file mode 100644
index 0000000000..96887f8f5f
--- /dev/null
+++ b/test/lisp/custom-tests.el
@@ -0,0 +1,87 @@
+;;; custom-tests.el --- tests for custom.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest custom-theme--load-path ()
+  "Test `custom-theme--load-path' behavior."
+  (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t))))
+    (unwind-protect
+        ;; Create all temporary files under the same deletable parent.
+        (let ((temporary-file-directory tmpdir))
+          ;; Path is empty.
+          (let ((custom-theme-load-path ()))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises non-existent file.
+          (let* ((name (make-temp-name tmpdir))
+                 (custom-theme-load-path (list name)))
+            (should (not (file-exists-p name)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing file.
+          (let* ((file (make-temp-file "file"))
+                 (custom-theme-load-path (list file)))
+            (should (file-exists-p file))
+            (should (not (file-directory-p file)))
+            (should (null (custom-theme--load-path))))
+
+          ;; Path comprises existing directory.
+          (let* ((dir (make-temp-file "dir" t))
+                 (custom-theme-load-path (list dir)))
+            (should (file-directory-p dir))
+            (should (equal (custom-theme--load-path) custom-theme-load-path)))
+
+          ;; Expand `custom-theme-directory' path element.
+          (let ((custom-theme-load-path '(custom-theme-directory)))
+            (let ((custom-theme-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "file")))
+              (should (file-exists-p custom-theme-directory))
+              (should (not (file-directory-p custom-theme-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((custom-theme-directory (make-temp-file "dir" t)))
+              (should (file-directory-p custom-theme-directory))
+              (should (equal (custom-theme--load-path)
+                             (list custom-theme-directory)))))
+
+          ;; Expand t path element.
+          (let ((custom-theme-load-path '(t)))
+            (let ((data-directory (make-temp-name tmpdir)))
+              (should (not (file-exists-p data-directory)))
+              (should (null (custom-theme--load-path))))
+            (let ((data-directory tmpdir)
+                  (themedir (expand-file-name "themes" tmpdir)))
+              (should (not (file-exists-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (with-temp-file themedir)
+              (should (file-exists-p themedir))
+              (should (not (file-directory-p themedir)))
+              (should (null (custom-theme--load-path)))
+              (delete-file themedir)
+              (make-directory themedir)
+              (should (file-directory-p themedir))
+              (should (equal (custom-theme--load-path) (list themedir))))))
+      (when (file-directory-p tmpdir)
+        (delete-directory tmpdir t)))))
+
+;;; custom-tests.el ends here
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0004-lisp-custom.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 7797 bytes --]

From c160ae70cf26be48ff23dc5ebb700eb819df58c9 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 16:09:57 +0100
Subject: [PATCH 4/8] * lisp/custom.el: Use lexical-binding

Remove duplicate 'Custom Themes' comment heading.
(deftheme, custom-declare-theme): Fix advertised calling convention.
(custom-enabled-themes): Fix message grammar.
---
 lisp/custom.el | 50 +++++++++++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 4536788eb2..1c667c8aa2 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1,4 +1,4 @@
-;;; custom.el --- tools for declaring and initializing options
+;;; custom.el --- tools for declaring and initializing options  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 1996-1997, 1999, 2001-2018 Free Software Foundation,
 ;; Inc.
@@ -150,7 +150,7 @@ custom-declare-variable
     (put symbol 'force-value nil))
   (if (keywordp doc)
       (error "Doc string is missing"))
-  (let ((initialize 'custom-initialize-reset)
+  (let ((initialize #'custom-initialize-reset)
 	(requests nil))
     (unless (memq :group args)
       (custom-add-to-group (custom-current-group) symbol 'custom-variable))
@@ -426,7 +426,7 @@ custom-current-group
 (defun custom-declare-group (symbol members doc &rest args)
   "Like `defgroup', but SYMBOL is evaluated as a normal argument."
   (while members
-    (apply 'custom-add-to-group symbol (car members))
+    (apply #'custom-add-to-group symbol (car members))
     (setq members (cdr members)))
   (when doc
     ;; This text doesn't get into DOC.
@@ -618,11 +618,8 @@ custom-note-var-changed
 The result is that the change is treated as having been made through Custom."
   (put variable 'customized-value (list (custom-quote (eval variable)))))
 
-\f
-;;; Custom Themes
-
-;;; Loading files needed to customize a symbol.
-;;; This is in custom.el because menu-bar.el needs it for toggle cmds.
+;; Loading files needed to customize a symbol.
+;; This is in custom.el because menu-bar.el needs it for toggle cmds.
 
 (defvar custom-load-recursion nil
   "Hack to avoid recursive dependencies.")
@@ -715,7 +712,7 @@ customize-mark-to-save
 
 Return non-nil if the `saved-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (saved (get symbol 'saved-value))
 	 (standard (get symbol 'standard-value))
@@ -744,7 +741,7 @@ customize-mark-as-set
 
 Return non-nil if the `customized-value' property actually changed."
   (custom-load-symbol symbol)
-  (let* ((get (or (get symbol 'custom-get) 'default-value))
+  (let* ((get (or (get symbol 'custom-get) #'default-value))
 	 (value (funcall get symbol))
 	 (customized (get symbol 'customized-value))
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
@@ -776,7 +773,7 @@ custom-reevaluate-setting
   ;; always do the funcall step, even if symbol was not bound before.
   (or (default-boundp symbol)
       (eval `(defvar ,symbol nil))) ; reset below, so any value is fine
-  (funcall (or (get symbol 'custom-set) 'set-default)
+  (funcall (or (get symbol 'custom-set) #'set-default)
 	   symbol
 	   (eval (car (or (get symbol 'saved-value) (get symbol 'standard-value))))))
 
@@ -946,7 +943,7 @@ custom-set-variables
 REQUEST is a list of features we must require in order to
 handle SYMBOL properly.
 COMMENT is a comment string about SYMBOL."
-  (apply 'custom-theme-set-variables 'user args))
+  (apply #'custom-theme-set-variables 'user args))
 
 (defun custom-theme-set-variables (theme &rest args)
   "Initialize variables for theme THEME according to settings in ARGS.
@@ -994,8 +991,8 @@ custom-theme-set-variables
 	       set)
 	  (when requests
 	    (put symbol 'custom-requests requests)
-	    (mapc 'require requests))
-	  (setq set (or (get symbol 'custom-set) 'custom-set-default))
+            (mapc #'require requests))
+          (setq set (or (get symbol 'custom-set) #'custom-set-default))
 	  (put symbol 'saved-value (list value))
 	  (put symbol 'saved-variable-comment comment)
 	  ;; Allow for errors in the case where the setter has
@@ -1091,26 +1088,29 @@ custom--sort-vars-1
 ;; they were used to supply keyword-value pairs like `:immediate',
 ;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
 
-(defmacro deftheme (theme &optional doc &rest ignored)
+(defmacro deftheme (theme &optional doc &rest _ignored)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
-  (declare (doc-string 2))
+  (declare (doc-string 2)
+           (advertised-calling-convention (theme &optional doc) "22.1"))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest ignored)
+(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
+  (declare (advertised-calling-convention (theme feature &optional doc) "22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
-  (add-to-list 'custom-known-themes theme)
+  (unless (memq theme custom-known-themes)
+    (push theme custom-known-themes))
   (put theme 'theme-feature feature)
   (when doc (put theme 'theme-documentation doc)))
 
@@ -1218,7 +1218,7 @@ load-theme
   (interactive
    (list
     (intern (completing-read "Load custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))
     nil nil))
   (unless (custom-theme-name-valid-p theme)
@@ -1411,9 +1411,9 @@ custom-enabled-themes
 			    themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
-	   (if failures
-	       (message "Failed to enable theme: %s"
-			(mapconcat 'symbol-name failures ", "))))))
+           (when failures
+             (message "Failed to enable theme(s): %s"
+                      (mapconcat #'symbol-name failures ", "))))))
 
 (defsubst custom-theme-enabled-p (theme)
   "Return non-nil if THEME is enabled."
@@ -1425,7 +1425,7 @@ disable-theme
   (interactive (list (intern
 		      (completing-read
 		       "Disable custom theme: "
-		       (mapcar 'symbol-name custom-enabled-themes)
+                       (mapcar #'symbol-name custom-enabled-themes)
 		       nil t))))
   (when (custom-theme-enabled-p theme)
     (let ((settings (get theme 'theme-settings)))
@@ -1491,7 +1491,7 @@ custom-theme-recalc-variable
     (if (and valspec
 	     (or (get variable 'force-value)
 		 (default-boundp variable)))
-	(funcall (or (get variable 'custom-set) 'set-default) variable
+        (funcall (or (get variable 'custom-set) #'set-default) variable
 		 (eval (car valspec))))))
 
 (defun custom-theme-recalc-face (face)
@@ -1532,7 +1532,7 @@ custom-reset-variables
     (VARIABLE IGNORED)
 
 This means reset VARIABLE.  (The argument IGNORED is ignored)."
-    (apply 'custom-theme-reset-variables 'user args))
+    (apply #'custom-theme-reset-variables 'user args))
 
 ;;; The End.
 
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0005-lisp-cus-theme.el-Use-lexical-binding.patch --]
[-- Type: text/x-diff, Size: 5907 bytes --]

From f0d70f5c4834ba5baff668ea2ee171eed7faea81 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 11 May 2018 15:35:09 +0100
Subject: [PATCH 5/8] * lisp/cus-theme.el: Use lexical-binding

---
 lisp/cus-theme.el | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index e5e787771b..53389956ad 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -1,4 +1,4 @@
-;;; cus-theme.el -- custom theme creation user interface
+;;; cus-theme.el -- custom theme creation user interface  -*- lexical-binding: t -*-
 ;;
 ;; Copyright (C) 2001-2018 Free Software Foundation, Inc.
 ;;
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) 'custom-theme-revert))
+  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -118,13 +118,13 @@ customize-create-theme
 		 :tag " Visit Theme "
 		 :help-echo "Insert the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-visit-theme)))
+                           (call-interactively #'custom-theme-visit-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Merge Theme "
 		 :help-echo "Merge in the settings of a pre-defined theme."
 		 :action (lambda (_widget &optional _event)
-			   (call-interactively 'custom-theme-merge-theme)))
+                           (call-interactively #'custom-theme-merge-theme)))
   (widget-insert "  ")
   (widget-create 'push-button
 		 :tag " Revert "
@@ -142,7 +142,7 @@ customize-create-theme
 	(widget-create 'text
 		       :value (format-time-string "Created %Y-%m-%d.")))
   (widget-create 'push-button
-     		 :notify (function custom-theme-write)
+                 :notify #'custom-theme-write
      		 " Save Theme ")
   (when (eq theme 'user)
     (setq custom-theme--migrate-settings t)
@@ -188,7 +188,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-face)))
+                             (call-interactively #'custom-theme-add-face)))
 
     ;; If THEME is non-nil, insert all of that theme's variables.
     (widget-insert "\n\n  Theme variables:\n ")
@@ -207,7 +207,7 @@ customize-create-theme
 		   :mouse-face 'highlight
 		   :pressed-face 'highlight
 		   :action (lambda (_widget &optional _event)
-			     (call-interactively 'custom-theme-add-variable)))
+                             (call-interactively #'custom-theme-add-variable)))
     (widget-insert ?\n)
     (widget-setup)
     (goto-char (point-min))
@@ -254,7 +254,7 @@ custom-theme-add-var-1
 			     :tag (custom-unlispify-tag-name symbol)
 			     :value symbol
 			     :shown-value (list val)
-			     :notify 'ignore
+                             :notify #'ignore
 			     :custom-level 0
 			     :custom-state 'hidden
 			     :custom-style 'simple))
@@ -313,7 +313,7 @@ custom-theme-visit-theme
   (interactive
    (list
     (intern (completing-read "Find custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "No valid theme named `%s'" theme))
@@ -328,7 +328,7 @@ custom-theme-merge-theme
   (interactive
    (list
     (intern (completing-read "Merge custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (eq theme 'user)
     (unless (custom-theme-name-valid-p theme)
@@ -343,8 +343,8 @@ custom-theme-merge-theme
 		     (memq name '(custom-enabled-themes
 				  custom-safe-themes)))
 	  (funcall (if option
-		       'custom-theme-add-variable
-		     'custom-theme-add-face)
+                       #'custom-theme-add-variable
+                     #'custom-theme-add-face)
 		   name value)))))
   theme)
 
@@ -475,7 +475,7 @@ describe-theme
   (interactive
    (list
     (intern (completing-read "Describe custom theme: "
-			     (mapcar 'symbol-name
+                             (mapcar #'symbol-name
 				     (custom-available-themes))))))
   (unless (custom-theme-name-valid-p theme)
     (error "Invalid theme name `%s'" theme))
@@ -616,11 +616,11 @@ customize-themes
   (widget-create 'push-button
 		 :tag " Save Theme Settings "
 		 :help-echo "Save the selected themes for future sessions."
-		 :action 'custom-theme-save)
+                 :action #'custom-theme-save)
   (widget-insert ?\n)
   (widget-create 'checkbox
 		 :value custom-theme-allow-multiple-selections
-		 :action 'custom-theme-selections-toggle)
+                 :action #'custom-theme-selections-toggle)
   (widget-insert (propertize " Select more than one theme at a time"
 			     'face '(variable-pitch (:height 0.9))))
 
@@ -632,13 +632,13 @@ customize-themes
 				  :value (custom-theme-enabled-p theme)
 				  :theme-name theme
 				  :help-echo help-echo
-				  :action 'custom-theme-checkbox-toggle))
+                                  :action #'custom-theme-checkbox-toggle))
       (push (cons theme widget) custom--listed-themes)
       (widget-create-child-and-convert widget 'push-button
 				       :button-face-get 'ignore
 				       :mouse-face-get 'ignore
 				       :value (format " %s" theme)
-				       :action 'widget-parent-action
+                                       :action #'widget-parent-action
 				       :help-echo help-echo)
       (widget-insert " -- "
 		     (propertize (custom-theme-summary theme)
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0006-Minor-custom.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 7892 bytes --]

From 3ace45ec8797dce64f5bcc33eaeb423c11b0aa71 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 31 May 2018 18:37:02 +0100
Subject: [PATCH 6/8] Minor custom.el simplifications

* lisp/custom.el (custom-quote): Duplicate macroexp-quote.
(custom-load-symbol, customize-mark-to-save, customize-mark-as-set)
(custom-theme-name-valid-p, enable-theme, custom-enabled-themes)
(disable-theme): Simplify logic.
---
 lisp/custom.el | 103 ++++++++++++++++++++++---------------------------
 1 file changed, 46 insertions(+), 57 deletions(-)

diff --git a/lisp/custom.el b/lisp/custom.el
index 1c667c8aa2..a08f7fda70 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -630,14 +630,12 @@ custom-load-symbol
     (let ((custom-load-recursion t))
       ;; Load these files if not already done,
       ;; to make sure we know all the dependencies of SYMBOL.
-      (condition-case nil
-	  (require 'cus-load)
-	(error nil))
-      (condition-case nil
-	  (require 'cus-start)
-	(error nil))
+      (ignore-errors
+        (require 'cus-load))
+      (ignore-errors
+        (require 'cus-start))
       (dolist (load (get symbol 'custom-loads))
-	(cond ((symbolp load) (condition-case nil (require load) (error nil)))
+        (cond ((symbolp load) (ignore-errors (require load)))
 	      ;; This is subsumed by the test below, but it's much faster.
 	      ((assoc load load-history))
 	      ;; This was just (assoc (locate-library load) load-history)
@@ -655,7 +653,7 @@ custom-load-symbol
 	      ;; We are still loading it when we call this,
 	      ;; and it is not in load-history yet.
 	      ((equal load "cus-edit"))
-	      (t (condition-case nil (load load) (error nil))))))))
+              (t (ignore-errors (load load))))))))
 \f
 (defvar custom-local-buffer nil
   "Non-nil, in a Customization buffer, means customize a specific buffer.
@@ -688,16 +686,12 @@ custom-set-minor-mode
 
 (defun custom-quote (sexp)
   "Quote SEXP if it is not self quoting."
-  (if (or (memq sexp '(t nil))
-	  (keywordp sexp)
-	  (and (listp sexp)
-	       (memq (car sexp) '(lambda)))
-	  (stringp sexp)
-	  (numberp sexp)
-	  (vectorp sexp)
-;;;  	  (and (fboundp 'characterp)
-;;;  	       (characterp sexp))
-	  )
+  ;; Can't use `macroexp-quote' because it is loaded after `custom.el'
+  ;; during bootstrap.  See `loadup.el'.
+  (if (and (not (consp sexp))
+           (or (keywordp sexp)
+               (not (symbolp sexp))
+               (booleanp sexp)))
       sexp
     (list 'quote sexp)))
 
@@ -718,12 +712,10 @@ customize-mark-to-save
 	 (standard (get symbol 'standard-value))
 	 (comment (get symbol 'customized-variable-comment)))
     ;; Save default value if different from standard value.
-    (if (or (null standard)
-	    (not (equal value (condition-case nil
-				  (eval (car standard))
-				(error nil)))))
-	(put symbol 'saved-value (list (custom-quote value)))
-      (put symbol 'saved-value nil))
+    (put symbol 'saved-value
+         (unless (and standard
+                      (equal value (ignore-errors (eval (car standard)))))
+           (list (custom-quote value))))
     ;; Clear customized information (set, but not saved).
     (put symbol 'customized-value nil)
     ;; Save any comment that might have been set.
@@ -747,9 +739,8 @@ customize-mark-as-set
 	 (old (or (get symbol 'saved-value) (get symbol 'standard-value))))
     ;; Mark default value as set if different from old value.
     (if (not (and old
-                  (equal value (condition-case nil
-                                   (eval (car old))
-                                 (error nil)))))
+                  (equal value (ignore-errors
+                                 (eval (car old))))))
 	(progn (put symbol 'customized-value (list (custom-quote value)))
 	       (custom-push-theme 'theme-value symbol 'user 'set
 				  (custom-quote value)))
@@ -1296,11 +1287,9 @@ custom-theme-load-confirm
 (defun custom-theme-name-valid-p (name)
   "Return t if NAME is a valid name for a Custom theme, nil otherwise.
 NAME should be a symbol."
-  (and (symbolp name)
-       name
-       (not (or (zerop (length (symbol-name name)))
-		(eq name 'user)
-		(eq name 'changed)))))
+  (and (not (memq name '(nil user changed)))
+       (symbolp name)
+       (not (string= "" (symbol-name name)))))
 
 (defun custom-available-themes ()
   "Return a list of Custom themes available for loading.
@@ -1356,8 +1345,8 @@ enable-theme
 		      (completing-read
 		       "Enable custom theme: "
 		       obarray (lambda (sym) (get sym 'theme-settings)) t))))
-  (if (not (custom-theme-p theme))
-      (error "Undefined Custom theme %s" theme))
+  (unless (custom-theme-p theme)
+    (error "Undefined Custom theme %s" theme))
   (let ((settings (get theme 'theme-settings)))
     ;; Loop through theme settings, recalculating vars/faces.
     (dolist (s settings)
@@ -1397,18 +1386,18 @@ custom-enabled-themes
 	 (let (failures)
 	   (setq themes (delq 'user (delete-dups themes)))
 	   ;; Disable all themes not in THEMES.
-	   (if (boundp symbol)
-	       (dolist (theme (symbol-value symbol))
-		 (if (not (memq theme themes))
-		     (disable-theme theme))))
+           (dolist (theme (and (boundp symbol)
+                               (symbol-value symbol)))
+             (unless (memq theme themes)
+               (disable-theme theme)))
 	   ;; Call `enable-theme' or `load-theme' on each of THEMES.
 	   (dolist (theme (reverse themes))
 	     (condition-case nil
 		 (if (custom-theme-p theme)
 		     (enable-theme theme)
 		   (load-theme theme))
-	       (error (setq failures (cons theme failures)
-			    themes (delq theme themes)))))
+               (error (push theme failures)
+                      (setq themes (delq theme themes)))))
 	   (enable-theme 'user)
 	   (custom-set-default symbol themes)
            (when failures
@@ -1441,23 +1430,23 @@ disable-theme
 	    ;; If the face spec specified by this theme is in the
 	    ;; saved-face property, reset that property.
 	    (when (equal (nth 3 s) (get symbol 'saved-face))
-	      (put symbol 'saved-face (and val (cadr (car val)))))))))
-      ;; Recompute faces on all frames.
-      (dolist (frame (frame-list))
-	;; We must reset the fg and bg color frame parameters, or
-	;; `face-set-after-frame-default' will use the existing
-	;; parameters, which could be from the disabled theme.
-	(set-frame-parameter frame 'background-color
-			     (custom--frame-color-default
-			      frame :background "background" "Background"
-			      "unspecified-bg" "white"))
-	(set-frame-parameter frame 'foreground-color
-			     (custom--frame-color-default
-			      frame :foreground "foreground" "Foreground"
-			      "unspecified-fg" "black"))
-	(face-set-after-frame-default frame))
-      (setq custom-enabled-themes
-	    (delq theme custom-enabled-themes)))))
+              (put symbol 'saved-face (cadar val))))))))
+    ;; Recompute faces on all frames.
+    (dolist (frame (frame-list))
+      ;; We must reset the fg and bg color frame parameters, or
+      ;; `face-set-after-frame-default' will use the existing
+      ;; parameters, which could be from the disabled theme.
+      (set-frame-parameter frame 'background-color
+                           (custom--frame-color-default
+                            frame :background "background" "Background"
+                            "unspecified-bg" "white"))
+      (set-frame-parameter frame 'foreground-color
+                           (custom--frame-color-default
+                            frame :foreground "foreground" "Foreground"
+                            "unspecified-fg" "black"))
+      (face-set-after-frame-default frame))
+    (setq custom-enabled-themes
+          (delq theme custom-enabled-themes))))
 
 ;; Only used if window-system not null.
 (declare-function x-get-resource "frame.c"
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0007-Minor-cus-theme.el-simplifications.patch --]
[-- Type: text/x-diff, Size: 3932 bytes --]

From b7a38177595b54b5312078df9f99eacf29572421 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Thu, 10 May 2018 03:08:10 +0100
Subject: [PATCH 7/8] Minor cus-theme.el simplifications

* lisp/cus-theme.el (custom-new-theme-mode, customize-themes)
(custom-theme-choose-mode): Use setq-local.
(customize-create-theme): Ditto.  Use delete-all-overlays.
(describe-theme-1, custom-theme-summary): Simplify logic.
---
 lisp/cus-theme.el | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 53389956ad..995c55b2b2 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -47,7 +47,7 @@ custom-new-theme-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-new-theme-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function) #'custom-theme-revert))
+  (setq-local revert-buffer-function #'custom-theme-revert))
 (put 'custom-new-theme-mode 'mode-class 'special)
 
 (defvar custom-theme-name nil)
@@ -93,15 +93,14 @@ customize-create-theme
   (switch-to-buffer (get-buffer-create (or buffer "*Custom Theme*")))
   (let ((inhibit-read-only t))
     (erase-buffer)
-    (dolist (ov (overlays-in (point-min) (point-max)))
-      (delete-overlay ov)))
+    (delete-all-overlays))
   (custom-new-theme-mode)
   (make-local-variable 'custom-theme-name)
-  (set (make-local-variable 'custom-theme--save-name) theme)
-  (set (make-local-variable 'custom-theme-faces) nil)
-  (set (make-local-variable 'custom-theme-variables) nil)
-  (set (make-local-variable 'custom-theme-description) "")
-  (set (make-local-variable 'custom-theme--migrate-settings) nil)
+  (setq-local custom-theme--save-name theme)
+  (setq-local custom-theme-faces nil)
+  (setq-local custom-theme-variables nil)
+  (setq-local custom-theme-description "")
+  (setq-local custom-theme--migrate-settings nil)
   (make-local-variable 'custom-theme-insert-face-marker)
   (make-local-variable 'custom-theme-insert-variable-marker)
   (make-local-variable 'custom-theme--listed-faces)
@@ -513,8 +512,7 @@ describe-theme-1
 			(condition-case nil
 			    (read (current-buffer))
 			  (end-of-file nil)))))
-	    (and sexp (listp sexp)
-		 (eq (car sexp) 'deftheme)
+            (and (eq (car-safe sexp) 'deftheme)
 		 (setq doc (nth 2 sexp)))))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
@@ -552,10 +550,10 @@ custom-theme-choose-mode
 Do not call this mode function yourself.  It is meant for internal use."
   (use-local-map custom-theme-choose-mode-map)
   (custom--initialize-widget-variables)
-  (set (make-local-variable 'revert-buffer-function)
-       (lambda (_ignore-auto noconfirm)
-	 (when (or noconfirm (y-or-n-p "Discard current choices? "))
-	   (customize-themes (current-buffer))))))
+  (setq-local revert-buffer-function
+              (lambda (_ignore-auto noconfirm)
+                (when (or noconfirm (y-or-n-p "Discard current choices? "))
+                  (customize-themes (current-buffer))))))
 (put 'custom-theme-choose-mode 'mode-class 'special)
 
 ;;;###autoload
@@ -568,7 +566,7 @@ customize-themes
   (let ((inhibit-read-only t))
     (erase-buffer))
   (custom-theme-choose-mode)
-  (set (make-local-variable 'custom--listed-themes) nil)
+  (setq-local custom--listed-themes nil)
   (make-local-variable 'custom-theme-allow-multiple-selections)
   (and (null custom-theme-allow-multiple-selections)
        (> (length custom-enabled-themes) 1)
@@ -662,8 +660,7 @@ custom-theme-summary
 			  (condition-case nil
 			      (read (current-buffer))
 			    (end-of-file nil)))))
-	      (and sexp (listp sexp)
-		   (eq (car sexp) 'deftheme)
+              (and (eq (car-safe sexp) 'deftheme)
 		   (setq doc (nth 2 sexp))))))))
     (cond ((null doc)
 	   "(no documentation available)")
-- 
2.18.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0008-Tweak-subr-x.el-substring-functions.patch --]
[-- Type: text/x-diff, Size: 4709 bytes --]

From 93f87046bddff2023550b4a9977a46cea86050e6 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios" <contovob@tcd.ie>
Date: Fri, 1 Jun 2018 21:58:10 +0100
Subject: [PATCH 8/8] Tweak subr-x.el substring functions

* lisp/emacs-lisp/subr-x.el (string-join): #'-quote function symbol.
(string-trim-left, string-trim-right):
Make better use of substring for minor speedup.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-test-string-trim-left, subr-x-test-string-trim-right)
(subr-x-test-string-remove-prefix)
(subr-x-test-string-remove-suffix): New tests.
---
 lisp/emacs-lisp/subr-x.el            | 12 +++----
 test/lisp/emacs-lisp/subr-x-tests.el | 47 ++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index e03a81c892..20eb0d5d05 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -211,7 +211,7 @@ string-empty-p
 
 (defsubst string-join (strings &optional separator)
   "Join all STRINGS using SEPARATOR."
-  (mapconcat 'identity strings separator))
+  (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
 
@@ -219,17 +219,17 @@ string-trim-left
   "Trim STRING of leading string matching REGEXP.
 
 REGEXP defaults to \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\`\\(?:" (or  regexp "[ \t\n\r]+")"\\)") string)
-      (replace-match "" t t string)
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
     string))
 
 (defsubst string-trim-right (string &optional regexp)
   "Trim STRING of trailing string matching REGEXP.
 
 REGEXP defaults to  \"[ \\t\\n\\r]+\"."
-  (if (string-match (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'") string)
-      (replace-match "" t t string)
-    string))
+  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+                           string)))
+    (if i (substring string 0 i) string)))
 
 (defsubst string-trim (string &optional trim-left trim-right)
   "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index f7f0ef384f..81467bab2d 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -532,6 +532,53 @@
                    (format "abs sum is: %s"))
                  "abs sum is: 15")))
 
+\f
+;; Substring tests
+
+(ert-deftest subr-x-test-string-trim-left ()
+  "Test `string-trim-left' behavior."
+  (should (equal (string-trim-left "") ""))
+  (should (equal (string-trim-left " \t\n\r") ""))
+  (should (equal (string-trim-left " \t\n\ra") "a"))
+  (should (equal (string-trim-left "a \t\n\r") "a \t\n\r"))
+  (should (equal (string-trim-left "" "") ""))
+  (should (equal (string-trim-left "a" "") "a"))
+  (should (equal (string-trim-left "aa" "a*") ""))
+  (should (equal (string-trim-left "ba" "a*") "ba"))
+  (should (equal (string-trim-left "aa" "a*?") "aa"))
+  (should (equal (string-trim-left "aa" "a+?") "a")))
+
+(ert-deftest subr-x-test-string-trim-right ()
+  "Test `string-trim-right' behavior."
+  (should (equal (string-trim-right "") ""))
+  (should (equal (string-trim-right " \t\n\r") ""))
+  (should (equal (string-trim-right " \t\n\ra") " \t\n\ra"))
+  (should (equal (string-trim-right "a \t\n\r") "a"))
+  (should (equal (string-trim-right "" "") ""))
+  (should (equal (string-trim-right "a" "") "a"))
+  (should (equal (string-trim-right "aa" "a*") ""))
+  (should (equal (string-trim-right "ab" "a*") "ab"))
+  (should (equal (string-trim-right "aa" "a*?") "")))
+
+(ert-deftest subr-x-test-string-remove-prefix ()
+  "Test `string-remove-prefix' behavior."
+  (should (equal (string-remove-prefix "" "") ""))
+  (should (equal (string-remove-prefix "" "a") "a"))
+  (should (equal (string-remove-prefix "a" "") ""))
+  (should (equal (string-remove-prefix "a" "b") "b"))
+  (should (equal (string-remove-prefix "a" "a") ""))
+  (should (equal (string-remove-prefix "a" "aa") "a"))
+  (should (equal (string-remove-prefix "a" "ab") "b")))
+
+(ert-deftest subr-x-test-string-remove-suffix ()
+  "Test `string-remove-suffix' behavior."
+  (should (equal (string-remove-suffix "" "") ""))
+  (should (equal (string-remove-suffix "" "a") "a"))
+  (should (equal (string-remove-suffix "a" "") ""))
+  (should (equal (string-remove-suffix "a" "b") "b"))
+  (should (equal (string-remove-suffix "a" "a") ""))
+  (should (equal (string-remove-suffix "a" "aa") "a"))
+  (should (equal (string-remove-suffix "a" "ba") "b")))
 
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
-- 
2.18.0


[-- Attachment #9: Type: text/plain, Size: 539 bytes --]


"Basil L. Contovounesios" <contovob@tcd.ie> writes:

> Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>
>>> Fair enough, though it's looking like the simplest solution is to keep
>>> the original (when (file-directory-p dir) ...) check and avoid cl-lib
>>> altogether.
>>
>> Agreed, with a comment explaining that cl-lib macros can't be used at
>> this point for bootstrap reasons.
>
> How's the attached (see [PATCH 3/8])?  Too verbose?

Anything holding this up on my end?
I reattach the patches for convenience.

Thanks,

-- 
Basil

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-07-03  7:57                                               ` Basil L. Contovounesios
@ 2018-07-11  1:40                                                 ` Stefan Monnier
  2018-07-11  6:05                                                   ` Basil L. Contovounesios
  0 siblings, 1 reply; 33+ messages in thread
From: Stefan Monnier @ 2018-07-11  1:40 UTC (permalink / raw)
  To: emacs-devel

> Anything holding this up on my end?
> I reattach the patches for convenience.

Looks good to me.  Do you have access rights to push, or do you need
someone else to do it?


        Stefan




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: Byte-compilation of custom themes
  2018-07-11  1:40                                                 ` Stefan Monnier
@ 2018-07-11  6:05                                                   ` Basil L. Contovounesios
  0 siblings, 0 replies; 33+ messages in thread
From: Basil L. Contovounesios @ 2018-07-11  6:05 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Anything holding this up on my end?
>> I reattach the patches for convenience.
>
> Looks good to me.  Do you have access rights to push, or do you need
> someone else to do it?

The latter, thanks.

-- 
Basil



^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2018-07-11  6:05 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-01-20 21:01 Byte-compilation of custom themes Basil L. Contovounesios
2018-01-24 16:16 ` Stefan Monnier
2018-01-30 22:16   ` Basil L. Contovounesios
2018-01-31  2:26     ` Stefan Monnier
2018-02-01  0:45       ` Basil L. Contovounesios
2018-02-02 14:25         ` Stefan Monnier
2018-05-10  2:49           ` Basil L. Contovounesios
2018-05-10  2:54             ` Basil L. Contovounesios
2018-05-11 14:07               ` Eli Zaretskii
2018-05-11 14:02             ` Eli Zaretskii
2018-05-11 15:16               ` Basil L. Contovounesios
2018-05-11 16:03                 ` Stefan Monnier
2018-05-11 20:03                   ` Basil L. Contovounesios
2018-05-11 17:32                 ` Eli Zaretskii
2018-05-11 20:43                   ` Basil L. Contovounesios
2018-05-12  7:04                     ` Eli Zaretskii
2018-06-01 20:48                       ` Basil L. Contovounesios
2018-06-01 21:07                         ` Basil L. Contovounesios
2018-06-02 11:24                         ` Eli Zaretskii
2018-06-02 18:53                           ` Basil L. Contovounesios
2018-06-02 19:32                             ` Eli Zaretskii
2018-06-02 20:02                               ` Basil L. Contovounesios
2018-06-03  3:52                               ` Stefan Monnier
2018-06-03 11:21                                 ` Basil L. Contovounesios
2018-06-03 15:11                                   ` Eli Zaretskii
2018-06-03 16:08                                     ` Basil L. Contovounesios
2018-06-03 16:16                                       ` Eli Zaretskii
2018-06-03 17:48                                         ` Basil L. Contovounesios
2018-06-03 20:22                                           ` Stefan Monnier
2018-06-04  1:33                                             ` Basil L. Contovounesios
2018-07-03  7:57                                               ` Basil L. Contovounesios
2018-07-11  1:40                                                 ` Stefan Monnier
2018-07-11  6:05                                                   ` Basil L. Contovounesios

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).