]> code.delx.au - gnu-emacs-elpa/commitdiff
Automatically determine the maximum face.
authorJackson Ray Hamilton <jackson@jacksonrayhamilton.com>
Sun, 21 Jun 2015 16:27:32 +0000 (09:27 -0700)
committerJackson Ray Hamilton <jackson@jacksonrayhamilton.com>
Sun, 21 Jun 2015 16:27:32 +0000 (09:27 -0700)
README.md
context-coloring.el
test/context-coloring-test.el

index 5975af0e0e2c10d51d74a3a31d754a2da0399fe8..38dbcfa2d65fa89fab1eb6dfb388a51d0629d73a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -42,8 +42,10 @@ then add the following to your init file:
 
 ## Color Schemes
 
-There is *no default color scheme*.  Define the colors according to your liking
-by setting the appropriate custom faces and the maximum face:
+You can define your own colors by customizing faces like
+`context-coloring-level-N-face`, where N is a number starting from 0.
+
+These are the colors used in the screenshot above:
 
 ```lisp
 (custom-theme-set-faces
@@ -59,7 +61,6 @@ by setting the appropriate custom faces and the maximum face:
  '(context-coloring-level-8-face  ((t :foreground "#9fc59f")))
  '(context-coloring-level-9-face  ((t :foreground "#d0bf8f")))
  '(context-coloring-level-10-face ((t :foreground "#dca3a3"))))
-(setq context-coloring-maximum-face 10)
 ```
 
 [See here](https://gist.github.com/jacksonrayhamilton/6b89ca3b85182c490816) for
index 5773b4094fdc052acb6fcc62612c485399c96c62..624f48661bb224a8f61e58d599b5b83c8752580c 100644 (file)
 
 ;;; Faces
 
-;; Create placeholder faces for users to populate.
-(dotimes (level 25)
+(defun context-coloring-defface (level light dark tty)
+  "Define a face for LEVEL with LIGHT, DARK and TTY colors."
   (let ((face (intern (format "context-coloring-level-%s-face" level)))
         (doc (format "Context coloring face, level %s." level)))
+    (custom-declare-face
+     face
+     `((((type tty)) (:foreground ,tty))
+       (((background light)) (:foreground ,light))
+       (((background dark)) (:foreground ,dark)))
+     doc
+     :group 'context-coloring)))
+
+;; Provide some default colors based off Emacs' defaults.
+(context-coloring-defface 0 "#000000" "#ffffff" nil)
+(context-coloring-defface 1 "#008b8b" "#00ffff" "yellow")
+(context-coloring-defface 2 "#0000ff" "#87cefa" "green")
+(context-coloring-defface 3 "#483d8b" "#b0c4de" "cyan")
+(context-coloring-defface 4 "#a020f0" "#eedd82" "blue")
+(context-coloring-defface 5 "#a0522d" "#98fb98" "magenta")
+(context-coloring-defface 6 "#228b22" "#7fffd4" "red")
+(context-coloring-defface 7 "#3f3f3f" "#cdcdcd" nil)
+
+(defconst context-coloring-default-maximum-face 7)
+
+;; Create placeholder faces for users and theme authors.
+(dotimes (level 18)
+  (let* ((level (+ level 8))
+         (face (intern (format "context-coloring-level-%s-face" level)))
+         (doc (format "Context coloring face, level %s." level)))
     (custom-declare-face face nil doc :group 'context-coloring)))
 
-(defvar context-coloring-maximum-face 24
-  "Index of the highest face available for coloring.")
+(defvar-local context-coloring-maximum-face nil
+  "Dynamic index of the highest face available for coloring.")
 
 (defsubst context-coloring-level-face (level)
   "Return the symbol for a face with LEVEL."
 `context-coloring-maximum-face'."
   (context-coloring-level-face (min level context-coloring-maximum-face)))
 
+(defconst context-coloring-level-face-regexp
+  "context-coloring-level-\\([[:digit:]]+\\)-face"
+  "Extract a level from a face.")
+
+(defun context-coloring-theme-highest-level (theme)
+  "Return the highest coloring level for THEME, or -1."
+  (let* ((settings (get theme 'theme-settings))
+         (tail settings)
+         face-string
+         number
+         (found -1))
+    (while tail
+      (and (eq (nth 0 (car tail)) 'theme-face)
+           (setq face-string (symbol-name (nth 1 (car tail))))
+           (string-match
+            context-coloring-level-face-regexp
+            face-string)
+           (setq number (string-to-number
+                         (substring face-string
+                                    (match-beginning 1)
+                                    (match-end 1))))
+           (> number found)
+           (setq found number))
+      (setq tail (cdr tail)))
+    found))
+
+(defun context-coloring-update-maximum-face ()
+  "Save the highest possible face for the current theme."
+  (let ((themes (append custom-enabled-themes '(user)))
+        (continue t)
+        theme
+        highest-level)
+    (while continue
+      (setq theme (car themes))
+      (setq themes (cdr themes))
+      (setq highest-level (context-coloring-theme-highest-level theme))
+      (setq continue (and themes (= highest-level -1))))
+    (setq context-coloring-maximum-face
+          (cond
+           ((= highest-level -1)
+            context-coloring-default-maximum-face)
+           (t
+            highest-level)))))
+
 
 ;;; Change detection
 
@@ -1080,6 +1149,7 @@ the current buffer, then execute it."
 (defun context-coloring-colorize ()
   "Color the current buffer by function context."
   (interactive)
+  (context-coloring-update-maximum-face)
   (context-coloring-dispatch))
 
 (defun context-coloring-colorize-with-buffer (buffer)
@@ -1145,11 +1215,10 @@ comments and strings, is still colored with `font-lock'.
 The entire buffer is colored initially.  Changes to the buffer
 trigger recoloring.
 
-Certain custom themes have predefined colors from their palettes
-to use for coloring.  See `context-coloring-theme-hash-table' for
-the supported themes.  If the currently-enabled custom theme is
-not among these, you can define colors for it with
-`context-coloring-define-theme', which see.
+Define your own colors by customizing faces like
+`context-coloring-level-N-face', where N is a number starting
+from 0.  If no face is found on a custom theme nor the `user'
+theme, the defaults are used.
 
 New language / major mode support can be added with
 `context-coloring-define-dispatch', which see.
index c84ae67213dccacf4d11d604e2b39eacd246b348..942d9889f9c87fde66e56e00e946f754b525a7c8 100644 (file)
@@ -304,6 +304,52 @@ which don't seem to have lexical binding.")
       (when (not torn-down)
         (ert-fail "Expected teardown function to have been called, but it wasn't.")))))
 
+(defun context-coloring-test-assert-maximum-face (expected)
+  "Assert that `context-coloring-maximum-face' is EXPECTED."
+  (when (not (= context-coloring-maximum-face expected))
+    (ert-fail (format "Expected maximum face to be %s, but it was %s"
+                      expected context-coloring-maximum-face))))
+
+(deftheme context-coloring-test-custom-theme)
+
+(context-coloring-test-define-derived-mode custom-theme)
+
+(context-coloring-test-deftest custom-theme
+  (lambda ()
+    (custom-theme-set-faces
+     'context-coloring-test-custom-theme
+     '(context-coloring-level-0-face ((t :foreground "#aaaaaa")))
+     '(context-coloring-level-1-face ((t :foreground "#bbbbbb"))))
+    (custom-set-faces
+     '(context-coloring-level-0-face ((t :foreground "#aaaaaa"))))
+    (enable-theme 'context-coloring-test-custom-theme)
+    (context-coloring-define-dispatch
+     'theme
+     :modes '(context-coloring-test-custom-theme-mode)
+     :colorizer #'ignore)
+    (context-coloring-test-custom-theme-mode)
+    (context-coloring-colorize)
+    (context-coloring-test-assert-maximum-face 1)
+    ;; This theme should now be ignored in favor of the `user' theme.
+    (custom-theme-reset-faces
+     'context-coloring-test-custom-theme
+     '(context-coloring-level-0-face nil)
+     '(context-coloring-level-1-face nil))
+    (context-coloring-colorize)
+    ;; Maximum face for `user'.
+    (context-coloring-test-assert-maximum-face 0)
+    ;; Now `user' should be ignored too.
+    (custom-reset-faces
+     '(context-coloring-level-0-face nil))
+    (context-coloring-colorize)
+    ;; Expect the package's defaults.
+    (context-coloring-test-assert-maximum-face
+     context-coloring-default-maximum-face))
+  :after (lambda ()
+           (custom-reset-faces
+            '(context-coloring-level-0-face nil))
+           (disable-theme 'context-coloring-test-custom-theme)))
+
 
 ;;; Coloring tests
 
@@ -314,7 +360,7 @@ which don't seem to have lexical binding.")
     (when (not (and face
                     (let* ((face-string (symbol-name face))
                            (matches (string-match
-                                     "context-coloring-level-\\([[:digit:]]+\\)-face"
+                                     context-coloring-level-face-regexp
                                      face-string)))
                       (when matches
                         (setq actual-level (string-to-number