emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/autothemer 5a193c796a: 0.2.11 - develop color grouping and


From: ELPA Syncer
Subject: [nongnu] elpa/autothemer 5a193c796a: 0.2.11 - develop color grouping and sorting. (#25)
Date: Fri, 2 Sep 2022 12:58:16 -0400 (EDT)

branch: elpa/autothemer
commit 5a193c796a5499a9b0aa0b40372d3746bc25fe39
Author: Jason Milkins <jasonm23@users.noreply.github.com>
Commit: GitHub <noreply@github.com>

    0.2.11 - develop color grouping and sorting. (#25)
    
    * 0.2.11 - develop color grouping and sorting.
---
 README.md                 |   5 +-
 autothemer.el             | 362 +++++++++++++++++++++---
 function-reference.md     | 696 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/autothemer-tests.el | 321 ++++++++++++++++-----
 4 files changed, 1270 insertions(+), 114 deletions(-)

diff --git a/README.md b/README.md
index 39466081d2..2fca846fb3 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,9 @@
 Autothemer provides `autothemer-deftheme` a macro wrapper for `deftheme` and
 `custom-theme-set-faces` which creates a custom color theme.
 
-The package also includes some useful theme development features... read on.
+The package also includes useful theme development features see below.
+
+---
 
 ## News
 
@@ -393,6 +395,7 @@ I'll add some more palette SVG templates in the Wiki, link 
to any more you creat
 
 [Wiki page here](/jasonm23/autothemer/wiki/Palette-SVG-Templates)
 
+### [Complete Command/Function Reference](function-reference.md)
 
 # TVA
 
diff --git a/autothemer.el b/autothemer.el
index 6bf5d5f45e..174f60394e 100644
--- a/autothemer.el
+++ b/autothemer.el
@@ -7,7 +7,7 @@
 ;; Maintainer: Jason Milkins <jasonm23@gmail.com>
 ;;
 ;; URL: https://github.com/jasonm23/autothemer
-;; Version: 0.2.10
+;; Version: 0.2.11
 ;; Package-Requires: ((dash "2.10.0") (emacs "26.1"))
 ;;
 ;;; License:
@@ -25,11 +25,26 @@
 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
-
-;; Reduces the amount of boilerplate code needed to define custom themes. Also
-;; provides the user with an interactive command that automatically generates
-;; face customization code using the theme's color palette.
-
+;;
+;; Reduce the amount of pain and boilerplate code needed to create custom 
themes using `autothemer-deftheme'.
+;;
+;; Autothemer also includes interactive commands and functions to
+;; assist with theme building, here are a few highlights...
+;;
+;; - Generate specs for unthemed faces using the theme color palette.
+;;   - `autothemer-generate-templates'
+;;   - `autothemer-generate-templates-filtered' (filter by regexp)
+;; - Generate a palette SVG image
+;;   - `autothemer-generate-palette-svg'
+;; - Insert a color name or color from the active palette
+;;   - `autothemer-insert-color-name'
+;;   - `autothemer-insert-color'
+;; - Colorize/font-lock palette color names in the buffer
+;;   - `autothemer-colorize'  (requires `rainbow-mode' during development.)
+;;
+;;
+;; Note in the function reference, the fucntion prefix `autothemer--' 
indicates internal
+;; functions.
 ;;; Code:
 (require 'cl-lib)
 (require 'dash)
@@ -48,17 +63,102 @@
   name
   description)
 
-(defvar autothemer--current-theme nil
+(defvar autothemer-current-theme nil
   "Internal variable of type `autothemer--theme' used by autothemer.
 Contains the color palette and the list of faces most recently
 customized using `autothemer-deftheme'.")
 
+(defvar autothemer-hue-groups
+  '((red             (345 . 10))
+    (red-orange      (10  . 20))
+    (orange-brown    (20  . 40))
+    (orange-yellow   (40  . 50))
+    (yellow          (50  . 60))
+    (yellow-green    (60  . 80))
+    (green           (80  . 140))
+    (green-cyan      (140 . 170))
+    (cyan            (170 . 200))
+    (cyan-blue       (200 . 220))
+    (blue            (220 . 240))
+    (blue-magenta    (240 . 280))
+    (magenta         (280 . 320))
+    (magenta-pink    (320 . 330))
+    (pink            (330 . 345)))
+  "Set of perceptual color ranges.")
+
+(defvar autothemer-simple-hue-groups
+  '((red     (345 . 20))
+    (orange  (20  . 50))
+    (yellow  (50  . 60))
+    (green   (60  . 140))
+    (cyan    (140 . 220))
+    (blue    (220 . 280))
+    (magenta (280 . 345)))
+  "Simple set of color groups.")
+
+(defvar autothemer-low-mid-high-saturation-groups
+  '((low (0.0 . 0.3333333333333333))
+    (mid (0.3333333333333334 . 0.6666666666666666))
+    (high (0.6666666666666667 . 1.0)))
+  "Low, mid & high saturation groups.")
+
+(defvar autothemer-20-percent-saturation-groups
+  '((saturation-000-020-percent (0.0 . 0.2))
+    (saturation-020-040-percent (0.2 . 0.4))
+    (saturation-040-060-percent (0.4 . 0.6))
+    (saturation-060-080-percent (0.6 . 0.8))
+    (saturation-080-100-percent (0.8 . 1.0)))
+  "Saturation grouping at 20% intervals.
+This is the default for `autothemer-saturation-group'.")
+
+(defvar autothemer-10-percent-saturation-groups
+  '((saturation-000-010-percent (0.0 . 0.1))
+    (saturation-010-020-percent (0.1 . 0.2))
+    (saturation-020-030-percent (0.2 . 0.3))
+    (saturation-030-040-percent (0.3 . 0.4))
+    (saturation-040-050-percent (0.4 . 0.5))
+    (saturation-050-060-percent (0.5 . 0.6))
+    (saturation-060-070-percent (0.6 . 0.7))
+    (saturation-070-080-percent (0.7 . 0.8))
+    (saturation-080-090-percent (0.8 . 0.9))
+    (saturation-090-100-percent (0.9 . 1.0)))
+  "Saturation grouping at 10% intervals.")
+
+(defvar autothemer-dark-mid-light-brightness-groups
+ '((dark (0.0 . 0.3333333333333333))
+   (mid (0.3333333333333334 . 0.6666666666666666))
+   (light (0.6666666666666667 . 1.0)))
+ "Dark, mid & light brightness groups.")
+
+(defvar autothemer-20-percent-brightness-groups
+  '((brightness-000-020-percent (0.0 . 0.2))
+    (brightness-020-040-percent (0.2 . 0.4))
+    (brightness-040-060-percent (0.4 . 0.6))
+    (brightness-060-080-percent (0.6 . 0.8))
+    (brightness-080-100-percent (0.8 . 1.0)))
+  "Brightness groups at 20% intervals.
+This is the default `autothemer-brightness-group'.")
+
+(defvar autothemer-10-percent-brightness-groups
+  '((brightness-000-010-percent (0.0 . 0.1))
+    (brightness-010-020-percent (0.1 . 0.2))
+    (brightness-020-030-percent (0.2 . 0.3))
+    (brightness-030-040-percent (0.3 . 0.4))
+    (brightness-040-050-percent (0.4 . 0.5))
+    (brightness-050-060-percent (0.5 . 0.6))
+    (brightness-060-070-percent (0.6 . 0.7))
+    (brightness-070-080-percent (0.7 . 0.8))
+    (brightness-080-090-percent (0.8 . 0.9))
+    (brightness-090-100-percent (0.9 . 1.0)))
+  "Brightness grouping at 10% intervals.")
+
 (defun autothemer--reduced-spec-to-facespec (display reduced-specs)
   "Create a face spec for DISPLAY, with specs REDUCED-SPECS.
-E.g., (autothemer--reduced-spec-to-facespec '(min-colors 60)
-'(button (:underline t :foreground red)))
--> `(button (((min-colors 60) (:underline ,t :foreground
-,red))))."
+
+For example:
+
+     (autothemer--reduced-spec-to-facespec '(min-colors 60) '(button 
(:underline t :foreground red)))
+     ;; => `(button (((min-colors 60) (:underline ,t :foreground ,red))))."
   (let* ((face (elt reduced-specs 0))
          (properties (elt reduced-specs 1))
          (spec (autothemer--demote-heads `(list (,display ,properties)))))
@@ -77,7 +177,7 @@ E.g., (a (b c d) e (f g)) -> (list a (list b c d) e (list f 
g))."
 ;;;###autoload
 (defmacro autothemer-deftheme (name description palette reduced-specs &rest 
body)
   "Define a theme NAME with description DESCRIPTION.
-A color PALETTE can be used to define let*-like
+A color PALETTE can be used to define `let*'-like
 bindings within both the REDUCED-SPECS and the BODY."
   (let* ((face-names (-map #'car reduced-specs))
          (color-names (-map #'car (-drop 1 palette)))
@@ -112,7 +212,7 @@ bindings within both the REDUCED-SPECS and the BODY."
                                                 in ,temp-defined-colors
                                                 collect 
(make-autothemer--color :name ,temp-colorname
                                                                                
 :value ,temp-color)))
-                                 (setq autothemer--current-theme
+                                 (setq autothemer-current-theme
                                        (make-autothemer--theme
                                         :name ,(symbol-name name)
                                         :description ,description
@@ -161,7 +261,7 @@ Iterate through all currently defined faces and return 
those that
 were left uncustomized by the most recent call to
 `autothemer-deftheme'."
   (let ((all-faces (face-list))
-        (themed-faces (autothemer--theme-defined-faces 
autothemer--current-theme)))
+        (themed-faces (autothemer--theme-defined-faces 
autothemer-current-theme)))
     (--filter (not (-contains? themed-faces it)) all-faces)))
 
 (defun autothemer--face-to-alist (face)
@@ -188,7 +288,7 @@ were left uncustomized by the most recent call to
   "Replace colors in REDUCED-SPEC by their closest approximations in THEME.
 Replace every expression in REDUCED-SPEC that passes
 `color-defined-p' by the closest approximation found in
-`autothemer--current-theme'.  Also quote all face names and
+`autothemer-current-theme'.  Also quote all face names and
 unbound symbols, such as `normal' or `demibold'."
   (let ((colors (autothemer--theme-colors theme))
         (face (car reduced-spec))
@@ -270,12 +370,12 @@ Calls `autothemer-generate-templates' after user provides 
REGEXP interactively."
   "Autogenerate customizations for unthemed faces (optionally by REGEXP).
 
 Generate customizations that approximate current face definitions using the
-nearest colors in the color palette of `autothemer--current-theme'.
+nearest colors in the color palette of `autothemer-current-theme'.
 
 An error is shown when no current theme is available."
   (interactive)
-  (unless autothemer--current-theme
-    (user-error "No autothemer--current-theme available. Please evaluate an 
autothemer-deftheme"))
+  (unless autothemer-current-theme
+    (user-error "No autothemer-current-theme available. Please evaluate an 
autothemer-deftheme"))
   (let* ((missing-faces
           (if (null regexp)
               (autothemer--unthemed-faces)
@@ -288,7 +388,7 @@ An error is shown when no current theme is available."
            (--map (autothemer--approximate-spec
                    (autothemer--alist-to-reduced-spec
                     it (autothemer--face-to-alist it))
-                   autothemer--current-theme)
+                   autothemer-current-theme)
                   missing-faces))
          (buffer
           (get-buffer-create
@@ -305,7 +405,7 @@ Otherwise, append NEW-COLUMN to every element of LISTS."
 
 (defun autothemer--current-theme-guard ()
   "Guard functions from executing when there's no current theme."
-  (unless autothemer--current-theme
+  (unless autothemer-current-theme
     (user-error "No current theme available. Evaluate an autotheme 
definition")))
 
 ;;; Get colors from theme palette
@@ -313,7 +413,7 @@ Otherwise, append NEW-COLUMN to every element of LISTS."
 (defun autothemer--get-color (color-name)
   "Return color palette object for (string) COLOR-NAME.
 
-Search the `autothemer--current-theme' color palette for COLOR-NAME
+Search the `autothemer-current-theme' color palette for COLOR-NAME
 and returns a color in the form of `autothemer--color' struct.
 
 See also `autothemer--color-p',
@@ -323,11 +423,11 @@ See also `autothemer--color-p',
   (--find
    (eql (intern color-name)
         (autothemer--color-name it))
-   (autothemer--theme-colors autothemer--current-theme)))
+   (autothemer--theme-colors autothemer-current-theme)))
 
 (defun autothemer--select-color (&optional prompt)
   "Select a color from the current palette, optionally use PROMPT.
-Current palette is read from `autothemer--current-theme'.
+Current palette is read from `autothemer-current-theme'.
 
 The selected color will be in the form of a `autothemer--color'
 
@@ -352,7 +452,7 @@ See also `autothemer--color-p',
                         'face (list ':background color
                                     ':foreground (readable-foreground-color 
color)))
                        name)))
-          (autothemer--theme-colors autothemer--current-theme))))
+          (autothemer--theme-colors autothemer-current-theme))))
        (color-name (cadr (split-string selected " " t " "))))
     (autothemer--get-color color-name)))
 
@@ -393,28 +493,28 @@ If PLIST is nil, ARGS are bound to BODY nil values."
 
 ;;; let palette...
 (defmacro autothemer-let-palette (&rest body)
-  "Provide a let block for BODY from `autothemer--current-theme'.
+  "Provide a let block for BODY from `autothemer-current-theme'.
 
 Load/eval the required autothemer theme source (not
-byte-compiled) to set `autothemer--current-theme'."
+byte-compiled) to set `autothemer-current-theme'."
   (autothemer--current-theme-guard)
   `(let ,(--map (list (autothemer--color-name it) (autothemer--color-value it))
-                (autothemer--theme-colors autothemer--current-theme))
+                (autothemer--theme-colors autothemer-current-theme))
      ,@body))
 
 ;;; Colorize alist for rainbow-mode
-(defun autothemer-colorize-alist ()
+(defun autothemer--colorize-alist ()
   "Generate an alist for use with rainbow-mode.
 
 To colorize use:
 
-    (rainbow-colorize-by-assoc (autothemer-colorize-alist))
+    (rainbow-colorize-by-assoc (autothemer--colorize-alist))
 
-Colors are from `autothemer--current-theme'."
+Colors are from `autothemer-current-theme'."
   (autothemer--current-theme-guard)
   (--map (cons (format "%s" (autothemer--color-name it))
                (autothemer--color-value it))
-    (autothemer--theme-colors autothemer--current-theme)))
+    (autothemer--theme-colors autothemer-current-theme)))
 
 (defvar autothemer--colors-font-lock-keywords nil)
 
@@ -422,8 +522,8 @@ Colors are from `autothemer--current-theme'."
   "Colorize using rainbow-mode."
   (interactive)
   (setq autothemer--colors-font-lock-keywords
-      `((,(regexp-opt (mapcar 'car (autothemer-colorize-alist)) 'words)
-         (0 (rainbow-colorize-by-assoc (autothemer-colorize-alist))))))
+      `((,(regexp-opt (mapcar 'car (autothemer--colorize-alist)) 'words)
+         (0 (rainbow-colorize-by-assoc (autothemer--colorize-alist))))))
   (font-lock-add-keywords nil autothemer--colors-font-lock-keywords t))
 
 (defun autothemer--color-to-hsv (rgb)
@@ -432,7 +532,7 @@ The `r' `g' `b' values can range between `0..65535'.
 
 In `(h s v)' `h', `s' and `v' are `0.0..1.0'."
   (cl-destructuring-bind
-      (r g b) rgb
+      (r g b) (--map (/ it 65535.0) rgb)
     (let*
         ((bri (max r g b))
          (delta (- bri (min r g b)))
@@ -455,8 +555,7 @@ In `(h s v)' `h', `s' and `v' are `0.0..1.0'."
             bri))))
 
 (defun autothemer-hex-to-rgb (hex)
-  "Fast convert HEX to `(r g b)'.
-(Perf equal to wx color values C function.)
+  "Convert HEX to `(r g b)'.
 `r', `g', `b' will be values `0..65535'"
   (let ((rgb (string-to-number (substring hex 1) 16)))
     (list
@@ -476,6 +575,8 @@ In `(h s v)' `h', `s' and `v' are `0.0..1.0'."
   "Return the HSV brightness of HEX-COLOR."
   (caddr (autothemer--color-to-hsv (autothemer-hex-to-rgb hex-color))))
 
+;;; Sort/Order of autothemer--color structs.
+
 (defun autothemer-darkest-order (a b)
   "Return t if the darkness of A > B."
   (let ((a (autothemer-color-brightness (autothemer--color-value a)))
@@ -521,12 +622,191 @@ There are also `autothemer-hue-order' and 
`autothemer-saturated-order'"
   (let ((fn (or fn 'autothemer-darkest-order)))
      (-sort fn theme-colors)))
 
+;; Color Grouping
+
+(defun autothemer-color-to-group (color fn groups)
+  "Group COLOR using FN, in GROUPS."
+  (let ((value (funcall fn color)))
+   (-reduce-from
+    (lambda (acc range)
+      (let ((a (car (cadr range)))
+            (b (cdr (cadr range))))
+       (if (<= a value b)
+         (car range)
+        acc)))
+    nil
+    groups)))
+
+(defun autothemer-saturation-group (color &optional saturation-groups)
+  "Return the saturation group of COLOR.
+Functionally identical to `autothemer-hue-groups' for saturation.
+Optionally provide a list of SATURATION-GROUPS.
+The default is `autothemer-20-percent-saturation-groups'."
+  (autothemer-color-to-group
+   color
+   'autothemer-color-sat
+   (or saturation-groups autothemer-20-percent-saturation-groups)))
+
+(defun autothemer-brightness-group (color &optional brightness-groups)
+  "Return the brightness group of COLOR.
+Functionally identical to `autothemer-hue-groups' for brightness.
+Optionally provide a list of BRIGHTNESS-GROUPS.
+The default is `autothemer-20-percent-brightness-groups'."
+  (autothemer-color-to-group
+   color
+   'autothemer-color-brightness
+   (or brightness-groups autothemer-20-percent-brightness-groups)))
+
+(defun autothemer-hue-group (color &optional hue-groups)
+  "Return the color hue group for COLOR.
+
+Optionally provide a list of HUE-GROUPS.
+\(default uses `autothemer-hue-groups'.)
+Also available is `autothemer-simple-hue-groups',
+both are customizable, or define your own.
+
+This facilitates hue grouping & sorting by a secondary axis.
+For example sort a list of colors by some axis (brightness or
+saturation). Then group by hue groups, and sort the groups.
+The format of each group in the list is:
+
+    (group-name (n1 . n2))
+
+Where `group-name' is a symbol to name the group,
+`(n1 . n2)' is a hue range specifier (in degrees)
+low `n1' to high `n2'.
+
+A hue range which crosses the apex (i.e. `360°..0°') is permitted."
+  (let* ((init-hue-groups (or (and (listp hue-groups) hue-groups)
+                              (and (listp (symbol-value hue-groups))
+                                   (symbol-value hue-groups))
+                              autothemer-hue-groups))
+         (hue-groups (-reduce-from
+                      (lambda (acc range)
+                        (let* ((a (car (cadr range)))
+                               (b (cdr (cadr range)))
+                               (r (if (> a b) ;; hue apex check 360..0
+                                      `(,(list (car range) (cons a 360))
+                                        ,(list (car range) (cons 0 b)))
+                                    `(,range))))
+                          (if acc
+                              (cl-concatenate 'list acc r)
+                            r)))
+                      nil
+                      init-hue-groups))
+         (hue (autothemer-color-hue color)))
+   (-reduce-from
+    (lambda (acc range)
+      (let ((a (car (cadr range)))
+            (b (cdr (cadr range))))
+       (if (<= a (* hue 360) b)
+         (car range)
+        acc)))
+    nil
+    hue-groups)))
+
+;;; Group and sort
+
+(defun autothemer-group-sort (groups sort-fn)
+  "Sort GROUPS of colors using SORT-FN.
+GROUPS are produced by `autothemer-group-colors'."
+  (mapcar
+    (lambda (group)
+      "Groups are alists with car as key, cdr as colors."
+      (let* ((name (car group))
+             (colors (cdr group))
+             (sorted-colors (--sort
+                             (funcall sort-fn it other)
+                             colors)))
+        (cons name sorted-colors)))
+    groups))
+
+(defun autothemer-group-colors (palette options)
+  "Group PALETTE colors into groups as defined in plist OPTIONS:
+`:group-fn' - mandatory group function
+`:group-args' - args for `group-fn'"
+  (autothemer--plist-bind (group-fn group-args) options
+   (let* ((colors-with-groups (mapcar (lambda (color)
+                                        (list (funcall group-fn 
(autothemer--color-value color)
+                                                       group-args)
+                                              color))
+                                palette))
+          (grouped-colors (mapcar (lambda (group) (--reduce (-flatten (cons 
acc (cdr it))) group))
+                                  (--group-by (car it) colors-with-groups))))
+        grouped-colors)))
+
+(defun autothemer-group-and-sort (palette options)
+  "Group and sort PALETTE using OPTIONS.
+
+Options is a plist of:
+
+    :group-fn - mandatory group function
+    :group-args - optional group args (to use a non-default group)
+    :sort-fn - optional sort function
+
+See color grouping functions and group lists:
+
+Hue grouping:
+
+    autothemer-hue-group
+
+Builtin hue groups:
+
+    autothemer-hue-groups
+    autothemer-simple-hue-groups
+
+Brightness grouping:
+
+    autothemer-brightness-group
+
+Builtin brightness groups:
+
+    autothemer-dark-mid-light-brightness-groups
+    autothemer-10-percent-brightness-groups
+    autothemer-20-percent-brightness-groups
+
+Saturation grouping:
+
+    autothemer-saturation-group
+
+Builtin saturation groups:
+
+    autothemer-low-mid-high-saturation-groups
+    autothemer-10-percent-saturation-groups
+    autothemer-20-percent-saturation-groups
+
+- - -
+
+Sorting:
+
+The sort/ordering functions take args A and B, which are expected
+to be `autothemer--color' structs.
+
+Darkest to lightest:      `(autothemer-darkest-order a b)'
+Lightest to darkest:      `(autothemer-lightest-order a b)'
+Hue:                      `(autothemer-hue-order a b)'
+Saturated to desaturated: `(autothemer-saturated-order a b)'
+Desaturated to saturated: `(autothemer-desaturated-order a b)'"
+ (autothemer--plist-bind
+  (group-fn
+   group-args
+   sort-fn)
+  options
+  (let* ((grouped-colors (autothemer-group-colors
+                          palette
+                          `(:group-fn ,group-fn
+                            :group-args ,group-args)))
+         (sorted-groups  (autothemer-group-sort
+                          grouped-colors
+                          sort-fn)))
+      sorted-groups)))
+
 ;;; SVG Palette generator...
 
 (defun autothemer-generate-palette-svg (&optional options)
   "Create an SVG palette image for a theme.
 
-Optionally supply a plist of OPTIONS (all keys are optional, 
+Optionally supply OPTIONS (a plist, all keys are optional,
 required values will default or prompt interactively.):
 
     :theme-file - theme filename
@@ -653,10 +933,10 @@ Swatch Template parameters:
                          |</g>
                          |")))
 
-            (autotheme-name (autothemer--theme-name autothemer--current-theme))
-            (colors (autothemer--theme-colors autothemer--current-theme))
-            (theme-name        (or theme-name (autothemer--theme-name 
autothemer--current-theme)))
-            (theme-description (or theme-description 
(autothemer--theme-description autothemer--current-theme)))
+            (autotheme-name (autothemer--theme-name autothemer-current-theme))
+            (colors (autothemer--theme-colors autothemer-current-theme))
+            (theme-name        (or theme-name (autothemer--theme-name 
autothemer-current-theme)))
+            (theme-description (or theme-description 
(autothemer--theme-description autothemer-current-theme)))
             (theme-url         (or theme-url (lm-homepage theme-file) 
(read-string "Enter theme URL: " "https://github.com/";)))
 
             (font-family        (or font-family        (read-string "Font 
family name: " "Helvetica Neue")))
diff --git a/function-reference.md b/function-reference.md
new file mode 100644
index 0000000000..457f130594
--- /dev/null
+++ b/function-reference.md
@@ -0,0 +1,696 @@
+# Autothemer
+
+Reduce the amount of pain and boilerplate code needed to create custom themes 
using `autothemer-deftheme`.
+
+Autothemer also includes interactive commands and functions to
+assist with theme building, here are a few highlights...
+
+- Generate specs for unthemed faces using the theme color palette.
+  - `autothemer-generate-templates`
+  - `autothemer-generate-templates-filtered` (filter by regexp)
+- Generate a palette SVG image
+  - `autothemer-generate-palette-svg`
+- Insert a color name or color from the active palette
+  - `autothemer-insert-color-name`
+  - `autothemer-insert-color`
+- Colorize/font-lock palette color names in the buffer
+  - `autothemer-colorize`  (requires `rainbow-mode` during development.)
+
+
+Note in the function reference, the fucntion prefix `autothemer--` indicates 
internal
+functions.
+ - - -
+## Functions
+
+### autothemer-colorize [command]
+
+Colorize using rainbow-mode.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-colorize)
+```
+
+- - -
+
+### autothemer-generate-palette-svg [command]
+
+Create an SVG palette image for a theme.
+
+Optionally supply `options` (a plist, all keys are optional,
+required values will default or prompt interactively.):
+
+    :theme-file - theme filename
+    :theme-name - override the title found in :theme-file
+    :theme-description - override the description found in :theme-file
+    :theme-url - override the url found in :theme-file
+    :swatch-width - px spacing width of a color swatch (default: 100)
+    :swatch-height - px spacing height of a color swatch (default: 150)
+    :swatch-rotate - degrees of rotation for swatch (default: 45)
+    :columns - number of columns for each palette row (default: 6)
+    :page-template - see page-template below
+    :page-top-margin - (default 120)
+    :page-right-margin - (default 30)
+    :page-bottom-margin - (default 60)
+    :page-left-margin - (default 30)
+    :h-space - (default 10)
+    :v-space - (default 10)
+    :swatch-template - see swatch-template below
+    :font-family - font name to use in the generated SVG
+    :bg-color
+    :text-color
+    :text-accent-color
+    :swatch-border-color
+    :sort-palette
+    :svg-out-file
+
+For advanced customization the :page-template and :swatch-template can be
+used to provide customize the SVG templates.
+
+Note: Template parameters are filled by `format` so we mark them as follows:
+
+Page Template parameters:
+
+    %1$s  - width
+    %2$s  - height
+    %3$s  - font-family
+    %4$s  - text-color
+    %5$s  - text-accent-color
+    %6$s  - bg-color
+    %7$s  - theme-name
+    %8$s  - theme-description
+    %9$s  - theme-url
+    %10$s - color swatches
+
+Swatch Template parameters:
+
+    %1$s - x
+    %2$s - y
+    %3$s - swatch-border-color
+    %4$s - swatch-color
+    %5$s - text-accent-color
+    %6$s - swatch-color-name
+
+<sup>function signature</sup>
+```lisp
+(autothemer-generate-palette-svg (&optional options))
+```
+
+- - -
+
+### autothemer-generate-templates [command]
+
+Autogenerate customizations for unthemed faces (optionally by `regexp`).
+
+Generate customizations that approximate current face definitions using the
+nearest colors in the color palette of `autothemer-current-theme`.
+
+An error is shown when no current theme is available.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-generate-templates (&optional regexp))
+```
+
+- - -
+
+### autothemer-generate-templates-filtered [command]
+
+Autogenerate customizations for unthemed faces matching `regexp`.
+
+Calls `autothemer-generate-templates` after user provides `regexp` 
interactively.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-generate-templates-filtered (regexp))
+```
+
+- - -
+
+### autothemer-insert-color [command]
+
+Select and insert a color from the current autotheme palette.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-insert-color)
+```
+
+- - -
+
+### autothemer-insert-color-name [command]
+
+Select and insert a color name from the current autotheme palette.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-insert-color-name)
+```
+
+- - -
+
+### autothemer-brightness-group
+
+Return the brightness group of `color`.
+Functionally identical to `autothemer-hue-groups` for brightness.
+Optionally provide a list of `brightness-groups`.
+The default is `autothemer-20-percent-brightness-groups`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-brightness-group (color &optional brightness-groups))
+```
+
+- - -
+
+### autothemer-color-brightness
+
+Return the HSV brightness of `hex-color`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-color-brightness (hex-color))
+```
+
+- - -
+
+### autothemer-color-hue
+
+Return the HSV hue of `hex-color`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-color-hue (hex-color))
+```
+
+- - -
+
+### autothemer-color-sat
+
+Return the HSV sat of `hex-color`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-color-sat (hex-color))
+```
+
+- - -
+
+### autothemer-color-to-group
+
+Group `color` using `fn`, in `groups`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-color-to-group (color fn groups))
+```
+
+- - -
+
+### autothemer-darkest-order
+
+Return t if the darkness of `a` > `b`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-darkest-order (a b))
+```
+
+- - -
+
+### autothemer-group-and-sort
+
+Group and sort `palette` using `options`.
+
+Options is a plist of:
+
+    :group-fn - mandatory group function
+    :group-args - optional group args (to use a non-default group)
+    :sort-fn - optional sort function
+
+See color grouping functions and group lists:
+
+Hue grouping:
+
+    autothemer-hue-group
+
+Builtin hue groups:
+
+    autothemer-hue-groups
+    autothemer-simple-hue-groups
+
+Brightness grouping:
+
+    autothemer-brightness-group
+
+Builtin brightness groups:
+
+    autothemer-dark-mid-light-brightness-groups
+    autothemer-10-percent-brightness-groups
+    autothemer-20-percent-brightness-groups
+
+Saturation grouping:
+
+    autothemer-saturation-group
+
+Builtin saturation groups:
+
+    autothemer-low-mid-high-saturation-groups
+    autothemer-10-percent-saturation-groups
+    autothemer-20-percent-saturation-groups
+
+- - -
+
+Sorting:
+
+The sort/ordering functions take args A and B, which are expected
+to be `autothemer--color` structs.
+
+Darkest to lightest:      `(autothemer-darkest-order a b)`
+Lightest to darkest:      `(autothemer-lightest-order a b)`
+Hue:                      `(autothemer-hue-order a b)`
+Saturated to desaturated: `(autothemer-saturated-order a b)`
+Desaturated to saturated: `(autothemer-desaturated-order a b)`
+
+<sup>function signature</sup>
+```lisp
+(autothemer-group-and-sort (palette options))
+```
+
+- - -
+
+### autothemer-group-colors
+
+Group `palette` colors into groups as defined in plist `options`:
+`:group-fn` - mandatory group function
+`:group-args` - args for `group-fn`
+
+<sup>function signature</sup>
+```lisp
+(autothemer-group-colors (palette options))
+```
+
+- - -
+
+### autothemer-group-sort
+
+Sort `groups` of colors using `sort-fn`.
+`groups` are produced by `autothemer-group-colors`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-group-sort (groups sort-fn))
+```
+
+- - -
+
+### autothemer-hex-to-rgb
+
+Convert `hex` to `(r g b)`.
+`r`, `g`, `b` will be values `0..65535`
+
+<sup>function signature</sup>
+```lisp
+(autothemer-hex-to-rgb (hex))
+```
+
+- - -
+
+### autothemer-hue-group
+
+Return the color hue group for `color`.
+
+Optionally provide a list of `hue-groups`.
+(default uses `autothemer-hue-groups`.)
+Also available is `autothemer-simple-hue-groups`,
+both are customizable, or define your own.
+
+This facilitates hue grouping & sorting by a secondary axis.
+For example sort a list of colors by some axis (brightness or
+saturation). Then group by hue groups, and sort the groups.
+The format of each group in the list is:
+
+    (group-name (n1 . n2))
+
+Where `group-name` is a symbol to name the group,
+`(n1 . n2)` is a hue range specifier (in degrees)
+low `n1` to high `n2`.
+
+A hue range which crosses the apex (i.e. `360°..0°`) is permitted.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-hue-group (color &optional hue-groups))
+```
+
+- - -
+
+### autothemer-hue-order
+
+Return t if the hue of `a` > `b`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-hue-order (a b))
+```
+
+- - -
+
+### autothemer-hue-sat-order
+
+Return t if the hue and sat of `a` > `b`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-hue-sat-order (a b))
+```
+
+- - -
+
+### autothemer-lightest-order
+
+Return t if the lightness of `a` > `b`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-lightest-order (a b))
+```
+
+- - -
+
+### autothemer-saturated-order
+
+Return t if the saturation of `a` > `b`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-saturated-order (a b))
+```
+
+- - -
+
+### autothemer-saturation-group
+
+Return the saturation group of `color`.
+Functionally identical to `autothemer-hue-groups` for saturation.
+Optionally provide a list of `saturation-groups`.
+The default is `autothemer-20-percent-saturation-groups`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer-saturation-group (color &optional saturation-groups))
+```
+
+- - -
+
+### autothemer-sort-palette
+
+Produce a list of sorted `theme-colors` using `fn`.
+
+If `fn` is nil, sort by default `fn` `autothemer-darkest-order`.
+
+`autothemer-lightest-order` is available to balance the force.
+
+There are also `autothemer-hue-order` and `autothemer-saturated-order`
+
+<sup>function signature</sup>
+```lisp
+(autothemer-sort-palette (theme-colors &optional fn))
+```
+
+- - -
+
+### autothemer--alist-to-reduced-spec [internal]
+
+Generate a reduced-spec for `facename`, based on the face attribute `alist`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--alist-to-reduced-spec (facename alist))
+```
+
+- - -
+
+### autothemer--approximate-spec [internal]
+
+Replace colors in `reduced-spec` by their closest approximations in `theme`.
+Replace every expression in `reduced-spec` that passes
+`color-defined-p` by the closest approximation found in
+`autothemer-current-theme`.  Also quote all face names and
+unbound symbols, such as `normal` or `demibold`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--approximate-spec (reduced-spec theme))
+```
+
+- - -
+
+### autothemer--color-distance [internal]
+
+Return the distance in rgb space between `color` and AUTOTHEMER-`color`.
+Here, `color` is an Emacs color specification and AUTOTHEMER-`color` is of
+type `autothemer--color`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--color-distance (color autothemer-color))
+```
+
+- - -
+
+### autothemer--color-to-hsv [internal]
+
+Convert `rgb`, a list of `(r g b)` to list `(h s v)`.
+The `r` `g` `b` values can range between `0..65535`.
+
+In `(h s v)` `h`, `s` and `v` are `0.0..1.0`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--color-to-hsv (rgb))
+```
+
+- - -
+
+### autothemer--colorize-alist [internal]
+
+Generate an alist for use with rainbow-mode.
+
+To colorize use:
+
+    (rainbow-colorize-by-assoc (autothemer--colorize-alist))
+
+Colors are from `autothemer-current-theme`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--colorize-alist)
+```
+
+- - -
+
+### autothemer--cons-to-tree [internal]
+
+Turn `the-cons` into a list, unless its cdr is `unspecified`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--cons-to-tree (the-cons))
+```
+
+- - -
+
+### autothemer--current-theme-guard [internal]
+
+Guard functions from executing when there's no current theme.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--current-theme-guard)
+```
+
+- - -
+
+### autothemer--demote-heads [internal]
+
+Demote every list head within `expr` by one element.
+E.g., (a (b c d) e (f g)) -> (list a (list b c d) e (list f g)).
+
+<sup>function signature</sup>
+```lisp
+(autothemer--demote-heads (expr))
+```
+
+- - -
+
+### autothemer--extract-display [internal]
+
+Extract from `palette` display specification #`n`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--extract-display (palette n))
+```
+
+- - -
+
+### autothemer--extract-let-block [internal]
+
+Extract a variable definition block from `palette` for display type `n`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--extract-let-block (palette n))
+```
+
+- - -
+
+### autothemer--face-to-alist [internal]
+
+Return the attribute alist for `face` in frame (selected-frame).
+
+<sup>function signature</sup>
+```lisp
+(autothemer--face-to-alist (face))
+```
+
+- - -
+
+### autothemer--fill-empty-palette-slots [internal]
+
+Fill empty `palette` slots so each display has all color-definitions.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--fill-empty-palette-slots (palette))
+```
+
+- - -
+
+### autothemer--find-closest-color [internal]
+
+Return the element of `colors` that is closest in rgb space to `color`.
+Here, `color` is an Emacs color specification and `colors` is a list
+of `autothemer--color` structs.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--find-closest-color (colors color))
+```
+
+- - -
+
+### autothemer--get-color [internal]
+
+Return color palette object for (string) `color-name`.
+
+Search the `autothemer-current-theme` color palette for `color-name`
+and returns a color in the form of `autothemer--color` struct.
+
+See also `autothemer--color-p`,
+         `autothemer--color-name`,
+         `autothemer--color-value`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--get-color (color-name))
+```
+
+- - -
+
+### autothemer--pad-with-nil [internal]
+
+Make sure that `row` has at least `min-number-of-elements`.
+Pad with nil if necessary.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--pad-with-nil (row min-number-of-elements))
+```
+
+- - -
+
+### autothemer--reduced-spec-to-facespec [internal]
+
+Create a face spec for `display`, with specs `reduced-specs`.
+
+For example:
+
+     (autothemer--reduced-spec-to-facespec '(min-colors 60) '(button 
(:underline t :foreground red)))
+     ;; => `(button (((min-colors 60) (:underline ,t :foreground ,red)))).
+
+<sup>function signature</sup>
+```lisp
+(autothemer--reduced-spec-to-facespec (display reduced-specs))
+```
+
+- - -
+
+### autothemer--replace-nil-by-precursor [internal]
+
+Replace nil colors in `palette-row` with their precursor.
+
+`palette-row` is of the form `(name color [color ...])`
+
+Where  the first `color` must be non nil.
+
+Any subsequent nil color will be replaced by the previous value.
+
+For example:
+
+     ("red-foo" "#FF0000" nil)
+
+Will become:
+
+     ("red-foo" "#FF0000" "#FF0000")
+
+<sup>function signature</sup>
+```lisp
+(autothemer--replace-nil-by-precursor (palette-row))
+```
+
+- - -
+
+### autothemer--select-color [internal]
+
+Select a color from the current palette, optionally use `prompt`.
+Current palette is read from `autothemer-current-theme`.
+
+The selected color will be in the form of a `autothemer--color`
+
+See also `autothemer--color-p`,
+         `autothemer--color-name`,
+         `autothemer--color-value`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--select-color (&optional prompt))
+```
+
+- - -
+
+### autothemer--unindent [internal]
+
+Unindent string `s` marked with | chars.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--unindent (s))
+```
+
+- - -
+
+### autothemer--unthemed-faces [internal]
+
+Find uncustomized faces.
+Iterate through all currently defined faces and return those that
+were left uncustomized by the most recent call to
+`autothemer-deftheme`.
+
+<sup>function signature</sup>
+```lisp
+(autothemer--unthemed-faces)
+```
+
+- - -
diff --git a/tests/autothemer-tests.el b/tests/autothemer-tests.el
index 03ab60faac..e120ff686d 100644
--- a/tests/autothemer-tests.el
+++ b/tests/autothemer-tests.el
@@ -1,10 +1,28 @@
 ;; autothemer-tests.el
 
+;; Version: 0.2.11
+
 ;;; Code:
 
 (require 'autothemer)
 
+;;; Test Helpers
+
+(defun name-color-to-struct (C)
+  "Cons C with name & value to `autothemer--color` struct."
+  (make-autothemer--color :name (car C) :value (cdr C)))
+
+(defun struct-to-cons-name-color (S)
+  "S (`autothemer--color` struct) to `(cons name color)'."
+  (cons
+   (autothemer--color-name S)
+   (autothemer--color-value S)))
+
+;;; Tests
+
 (progn "Test autothemer-deftheme"
+
+;;; Example theme
   (autothemer-deftheme theme-example
    "Autothemer example..."
 
@@ -38,54 +56,58 @@
         ,example-orange
         ,example-cyan])))
 
+;;; autothemer-current-theme is set.
+
   (ert-deftest current-theme ()
     "Test current theme is available."
     (should (not (null
-                  autothemer--current-theme))))
+                  autothemer-current-theme))))
 
   (ert-deftest theme-has-colors ()
     "Check theme has colors."
     (should (eql 7 (length (autothemer--theme-colors
-                            autothemer--current-theme)))))
+                            autothemer-current-theme)))))
 
   (ert-deftest theme-has-face-specs ()
     "Check theme has face specs."
     (should (eql 2 (length (autothemer--theme-defined-faces
-                            autothemer--current-theme)))))
+                            autothemer-current-theme)))))
 
   (ert-deftest color-value ()
     "Check color value."
     (should (string= "#781210"
                      (autothemer--color-value
                       (car (autothemer--theme-colors
-                            autothemer--current-theme))))))
+                            autothemer-current-theme))))))
 
   (ert-deftest color-name ()
     "Check color name."
     (should (string= "example-red"
                      (autothemer--color-name
                       (car (autothemer--theme-colors
-                            autothemer--current-theme))))))
+                            autothemer-current-theme))))))
 
   (ert-deftest spec-name ()
     "Check spec name."
     (should (equal 'button
                       (car (autothemer--theme-defined-faces
-                                  autothemer--current-theme)))))
+                                  autothemer-current-theme)))))
 
   (ert-deftest theme-has-description ()
     "Check theme description."
     (should (string=
              "Autothemer example..."
              (autothemer--theme-description
-              autothemer--current-theme))))
+              autothemer-current-theme))))
 
   (ert-deftest theme-has-name ()
     "Check theme name."
     (should (string=
              "theme-example"
              (autothemer--theme-name
-              autothemer--current-theme))))
+              autothemer-current-theme))))
+
+;;; Let palette
 
   (ert-deftest let-palette ()
     "Check autothemer-let-palette"
@@ -93,6 +115,8 @@
              "#781210"
              (autothemer-let-palette example-red))))
 
+;;; AT Helper functions
+
   (ert-deftest unindent ()
     "Test unindent."
     (should
@@ -109,69 +133,222 @@
      (should (eql a 1))
      (should (eql b 2))))
 
- (ert-deftest autothemer-color-hue ()
-  "Test get hue of hex-color."
-   (= (autothemer-color-hue "#FF0000") 0)
-   (= (autothemer-color-hue "#FFFF00") 0.16666666666666666)
-   (= (autothemer-color-hue "#00FF00") 0.33333333333333333)
-   (= (autothemer-color-hue "#0000FF") 0.66666666666666666))
-
- (ert-deftest autothemer-color-sat ()
-   "Test get sat of hex-color."
-   (= (autothemer-color-sat "#0000FF") 1.0)
-   (= (autothemer-color-sat "#FF00FF") 1.0)
-   (= (autothemer-color-sat "#778822") 0.75)
-   (= (autothemer-color-sat "#772288") 0.75)
-   (= (autothemer-color-sat "#112233") 0.6666666666666667))
-
- (ert-deftest autothemer-color-brightness ()
-   "Test get brightness of hex-color."
-   (= (autothemer-color-brightness "#0000FF") 1.0)
-   (= (autothemer-color-brightness "#00FF00") 1.0)
-   (= (autothemer-color-brightness "#FF00FF") 1.0)
-   (= (autothemer-color-brightness "#333333") 0.2)
-   (= (autothemer-color-brightness "#555555") 0.3333333333333333))
-
- (ert-deftest autothemer--color-distance ()
-   "Test color distance."
-   (let ((color-struct (make-autothemer--color :name "Test" :value "#100000")))
-    (should (eql (autothemer--color-distance "#100000" color-struct) 0))
-    (should (eql (autothemer--color-distance "#100001" color-struct) 257))
-    (should (eql (autothemer--color-distance "#000001" color-struct) 4369))
-    (should (eql (autothemer--color-distance "#FF0000" color-struct) 61423))))
-
- (ert-deftest autothemer-hex-to-rgb ()
-   "Test hex to rgb."
-  (should (equal '(0 0 0) (autothemer-hex-to-rgb "#000000")))
-  (should (equal '(65535 65535 65535) (autothemer-hex-to-rgb "#FFFFFF")))
-  (should (equal '(65535 0 0) (autothemer-hex-to-rgb "#FF0000")))
-  (should (equal '(65535 65535 0) (autothemer-hex-to-rgb "#FFFF00")))
-  (should (equal '(0 65535 0) (autothemer-hex-to-rgb "#00FF00")))
-  (should (equal '(0 65535 65535) (autothemer-hex-to-rgb "#00FFFF")))
-  (should (equal '(0 0 65535) (autothemer-hex-to-rgb "#0000FF")))
-  (should (equal '(32896 32896 32896) (autothemer-hex-to-rgb "#808080"))))
-
- (ert-deftest autothemer-colorize-alist ()
-   "Check autothemer-colorize-alist."
-   (should (equal '(("example-red" . "#781210")
-                    ("example-green" . "#22881F")
-                    ("example-blue" . "#212288")
-                    ("example-purple" . "#812FFF")
-                    ("example-yellow" . "#EFFE00")
-                    ("example-orange" . "#E06500")
-                    ("example-cyan" . "#22DDFF"))
-                  (autothemer-colorize-alist)))))
-
-;;; Example theme in memory:
-'(#s(autothemer--theme
-     (#s(autothemer--color example-red "#781210")
-        #s(autothemer--color example-green "#22881F")
-        #s(autothemer--color example-blue "#212288")
-        #s(autothemer--color example-purple "#812FFF")
-        #s(autothemer--color example-yellow "#EFFE00")
-        #s(autothemer--color example-orange "#E06500")
-        #s(autothemer--color example-cyan "#22DDFF"))
-     (button error)
-     "theme-example" "Autothemer example..."))
+;;; Color conversion
+
+  (ert-deftest autothemer-hex-to-rgb ()
+    "Test hex to rgb."
+   (should (equal '(0 0 0) (autothemer-hex-to-rgb "#000000")))
+   (should (equal '(65535 65535 65535) (autothemer-hex-to-rgb "#FFFFFF")))
+   (should (equal '(65535 0 0) (autothemer-hex-to-rgb "#FF0000")))
+   (should (equal '(65535 65535 0) (autothemer-hex-to-rgb "#FFFF00")))
+   (should (equal '(0 65535 0) (autothemer-hex-to-rgb "#00FF00")))
+   (should (equal '(0 65535 65535) (autothemer-hex-to-rgb "#00FFFF")))
+   (should (equal '(0 0 65535) (autothemer-hex-to-rgb "#0000FF")))
+   (should (equal '(32896 32896 32896) (autothemer-hex-to-rgb "#808080"))))
+
+  (ert-deftest autothemer--color-to-hsv ()
+    "Test color to hsv conversion."
+    (should (equal (autothemer--color-to-hsv '(0 0 0)) '(0.0 0.0 0.0)))
+    (should (equal (autothemer--color-to-hsv '(65535 65535 65535)) '(0.0 0.0 
1.0)))
+    (should (equal (autothemer--color-to-hsv '(0 0 65535)) 
'(0.6666666666666666 1.0 1.0)))
+    (should (equal (autothemer--color-to-hsv '(12896 0 32896)) 
'(0.7320038910505837 1.0 0.5019607843137255))))
+
+;;; HSV Color components
+
+  (ert-deftest autothemer-color-hue ()
+   "Test get hue of hex-color."
+    (should (= (autothemer-color-hue "#FF0000") 0))
+    (should (= (autothemer-color-hue "#FFFF00") 0.16666666666666666))
+    (should (= (autothemer-color-hue "#00FF00") 0.33333333333333333))
+    (should (= (autothemer-color-hue "#0000FF") 0.66666666666666666)))
+  
+  (ert-deftest autothemer-color-sat ()
+    "Test get sat of hex-color."
+    (should (= (autothemer-color-sat "#0000FF") 1.0))
+    (should (= (autothemer-color-sat "#FF00FF") 1.0))
+    (should (= (autothemer-color-sat "#778822") 0.75))
+    (should (= (autothemer-color-sat "#772288") 0.75))
+    (should (= (autothemer-color-sat "#112233") 0.6666666666666667)))
+  
+  (ert-deftest autothemer-color-brightness ()
+    "Test get brightness of hex-color."
+    (should (= (autothemer-color-brightness "#0000FF") 1.0))
+    (should (= (autothemer-color-brightness "#00FF00") 1.0))
+    (should (= (autothemer-color-brightness "#FF00FF") 1.0))
+    (should (= (autothemer-color-brightness "#333333") 0.2))
+    (should (= (autothemer-color-brightness "#555555") 0.3333333333333333)))
+
+;;; Color distance
+
+  (ert-deftest autothemer--color-distance ()
+    "Test color distance."
+    (let ((color-struct (make-autothemer--color :name "Test" :value 
"#100000")))
+     (should (eql (autothemer--color-distance "#100000" color-struct) 0))
+     (should (eql (autothemer--color-distance "#100001" color-struct) 257))
+     (should (eql (autothemer--color-distance "#000001" color-struct) 4369))
+     (should (eql (autothemer--color-distance "#FF0000" color-struct) 61423))))
+
+;;; Colorization
+
+  (ert-deftest autothemer--colorize-alist ()
+    "Check autothemer-colorize-alist."
+    (should (equal '(("example-red" . "#781210")
+                     ("example-green" . "#22881F")
+                     ("example-blue" . "#212288")
+                     ("example-purple" . "#812FFF")
+                     ("example-yellow" . "#EFFE00")
+                     ("example-orange" . "#E06500")
+                     ("example-cyan" . "#22DDFF"))
+                   (autothemer--colorize-alist))))
+
+;;; Color/Palette grouping & sorting
+
+  (ert-deftest autothemer-color-hue-group ()
+    "Test autothemer-color-hue-group."
+    (should (equal (autothemer-hue-group "#FF0005") 'red))
+    (should (equal (autothemer-hue-group "#00FF00") 'green))
+    (should (equal (autothemer-hue-group "#FF00FF") 'magenta))
+    (should (equal (autothemer-hue-group "#00FFFF") 'cyan))
+    (should (equal (autothemer-hue-group "#0000FF") 'blue-magenta))
+    (should (equal (autothemer-hue-group "#FFFF00") 'yellow-green))
+    (should (equal (autothemer-hue-group "#FFFF00" autothemer-hue-groups) 
'yellow-green))
+    (should (equal (autothemer-hue-group "#FFFF00" 
autothemer-simple-hue-groups) 'green)))
+
+  (ert-deftest autothemer-brightness-group ()
+    "Test autothemer-brightness-group."
+    (should (equal (autothemer-brightness-group "#FF0005") 
'brightness-080-100-percent))
+    (should (equal (autothemer-brightness-group "#007700") 
'brightness-040-060-percent))
+    (should (equal (autothemer-brightness-group "#FF55FF") 
'brightness-080-100-percent))
+    (should (equal (autothemer-brightness-group "#004444") 
'brightness-020-040-percent))
+    (should (equal (autothemer-brightness-group "#020202") 
'brightness-000-020-percent))
+    (should (equal (autothemer-brightness-group
+                    "#020202"
+                    autothemer-dark-mid-light-brightness-groups)
+                   'dark))
+    (should (equal (autothemer-brightness-group
+                    "#777777"
+                    autothemer-dark-mid-light-brightness-groups)
+                   'mid)))
+
+  (ert-deftest autothemer-saturation-group ()
+    "Test autothemer-saturation-group."
+    (should (equal (autothemer-saturation-group "#FF0005") 
'saturation-080-100-percent))
+    (should (equal (autothemer-saturation-group "#007700") 
'saturation-080-100-percent))
+    (should (equal (autothemer-saturation-group "#FF55FF") 
'saturation-060-080-percent))
+    (should (equal (autothemer-saturation-group "#004444") 
'saturation-080-100-percent))
+    (should (equal (autothemer-saturation-group "#020202") 
'saturation-000-020-percent))
+    (should (equal (autothemer-saturation-group
+                    "#020202"
+                    autothemer-low-mid-high-saturation-groups)
+                   'low))
+    (should (equal (autothemer-saturation-group
+                    "#336677"
+                    autothemer-low-mid-high-saturation-groups)
+                   'mid)))
+
+  (ert-deftest autothemer-group-colors ()
+    "Group colors into a plist of color lists, with group names as keys."
+    (should (equal
+                (autothemer-group-colors
+                 (list
+                  (make-autothemer--color :name 'example-color-005 :value 
"#112063")
+                  (make-autothemer--color :name 'example-color-006 :value 
"#88DDCC")
+                  (make-autothemer--color :name 'example-color-006 :value 
"#99DDCC")
+                  (make-autothemer--color :name 'example-color-006 :value 
"#FFDDCC")
+                  (make-autothemer--color :name 'example-color-006 :value 
"#FFEECC")
+                  (make-autothemer--color :name 'example-color-007 :value 
"#281993")
+                  (make-autothemer--color :name 'example-color-010 :value 
"#240933"))
+                 (list :group-fn 'autothemer-saturation-group
+                       :group-args autothemer-low-mid-high-saturation-groups))
+                '((high #s(autothemer--color example-color-005 "#112063")
+                        #s(autothemer--color example-color-007 "#281993")
+                        #s(autothemer--color example-color-010 "#240933"))
+                  (mid #s(autothemer--color example-color-006 "#88DDCC"))
+                  (low #s(autothemer--color example-color-006 "#99DDCC")
+                       #s(autothemer--color example-color-006 "#FFDDCC")
+                       #s(autothemer--color example-color-006 "#FFEECC"))))))
+
+  (ert-deftest autothemer-group-and-sort ()
+    "Group and sort a palette of `autothemer--color' structs."
+    (should (equal (autothemer-group-and-sort
+                     (mapcar
+                      'name-color-to-struct
+                      '((example-color-001 . "#702414")
+                        (example-color-002 . "#642C12")
+                        (example-color-003 . "#583410")
+                        (example-color-004 . "#191204")
+                        (example-color-005 . "#181818")
+                        (example-color-006 . "#191904")
+                        (example-color-007 . "#373D0A")
+                        (example-color-008 . "#243108")
+                        (example-color-009 . "#162506")
+                        (example-color-010 . "#224C0E")
+                        (example-color-011 . "#287C16")
+                        (example-color-012 . "#0E4C0E")
+                        (example-color-013 . "#147024")
+                        (example-color-014 . "#0E4C22")
+                        (example-color-015 . "#167C49")
+                        (example-color-016 . "#20BE87")
+                        (example-color-017 . "#28E4C4")
+                        (example-color-018 . "#1AA4A4")
+                        (example-color-019 . "#178297")
+                        (example-color-020 . "#2391CB")
+                        (example-color-021 . "#13416F")
+                        (example-color-022 . "#13306F")
+                        (example-color-023 . "#112063")
+                        (example-color-024 . "#0D0D4B")
+                        (example-color-025 . "#281993")
+                        (example-color-026 . "#170933")
+                        (example-color-027 . "#620FA9")
+                        (example-color-028 . "#240933")
+                        (example-color-029 . "#63136F")
+                        (example-color-030 . "#330933")
+                        (example-color-031 . "#971782")
+                        (example-color-032 . "#D62499")
+                        (example-color-033 . "#A41A5F")
+                        (example-color-034 . "#D82662")
+                        (example-color-035 . "#B11D37")
+                        (example-color-036 . "#E52929")))
+                    '(:group-fn autothemer-hue-group
+                      :group-args autothemer-simple-hue-groups
+                      :sort-fn autothemer-darkest-order))
+
+                   '((red #s(autothemer--color example-color-005 "#181818")
+                          #s(autothemer--color example-color-002 "#642C12")
+                          #s(autothemer--color example-color-001 "#702414")
+                          #s(autothemer--color example-color-035 "#B11D37")
+                          #s(autothemer--color example-color-036 "#E52929"))
+                     (orange #s(autothemer--color example-color-004 "#191204")
+                             #s(autothemer--color example-color-003 "#583410"))
+                     (green #s(autothemer--color example-color-006 "#191904")
+                            #s(autothemer--color example-color-009 "#162506")
+                            #s(autothemer--color example-color-008 "#243108")
+                            #s(autothemer--color example-color-007 "#373D0A")
+                            #s(autothemer--color example-color-010 "#224C0E")
+                            #s(autothemer--color example-color-012 "#0E4C0E")
+                            #s(autothemer--color example-color-014 "#0E4C22")
+                            #s(autothemer--color example-color-013 "#147024")
+                            #s(autothemer--color example-color-011 "#287C16"))
+                     (cyan #s(autothemer--color example-color-021 "#13416F")
+                           #s(autothemer--color example-color-015 "#167C49")
+                           #s(autothemer--color example-color-019 "#178297")
+                           #s(autothemer--color example-color-018 "#1AA4A4")
+                           #s(autothemer--color example-color-016 "#20BE87")
+                           #s(autothemer--color example-color-020 "#2391CB")
+                           #s(autothemer--color example-color-017 "#28E4C4"))
+                     (blue #s(autothemer--color example-color-026 "#170933")
+                           #s(autothemer--color example-color-028 "#240933")
+                           #s(autothemer--color example-color-024 "#0D0D4B")
+                           #s(autothemer--color example-color-023 "#112063")
+                           #s(autothemer--color example-color-022 "#13306F")
+                           #s(autothemer--color example-color-025 "#281993")
+                           #s(autothemer--color example-color-027 "#620FA9"))
+                     (magenta #s(autothemer--color example-color-030 "#330933")
+                              #s(autothemer--color example-color-029 "#63136F")
+                              #s(autothemer--color example-color-031 "#971782")
+                              #s(autothemer--color example-color-033 "#A41A5F")
+                              #s(autothemer--color example-color-032 "#D62499")
+                              #s(autothemer--color example-color-034 
"#D82662")))))))
+
 
 ;;; autothemer-tests.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]