git.fiddlerwoaroof.com
Raw Blame History
;;;; colors.lisp
(defpackage #:colors
  (:use #:cl)
  (:export #:colorscheme #:palette *palette*
           #:invert-palette
           #:let-palette #:with-palette
           #:accentize
           #:colorscheme-bg #:colorscheme-bg-highlight 
           #:colorscheme-fg-deemph #:colorscheme-fg #:colorscheme-fg-highlight 
           #:colorscheme-accent 
           #:colorscheme-hover-highlight))

(in-package #:colors)
(declaim (optimize (debug 2) (safety 2) (speed 0)))

;;; Generic utility macro TODO: separate these out!!!
(defmacro initialize-to (obj1-v obj2-v &body slot-swaps)
  (alexandria:with-gensyms (obj1 obj2)
    `(let* ((,obj1 ,obj1-v)
            (,obj2 ,obj2-v))
       ,@(loop for (to from) in slot-swaps
               collect `(setf (,to ,obj1) (,from ,obj2))))))

;;; This macro connects the "-" prefixed slots in the colorscheme class
;;; To the appropriate palette
(defmacro def-palette-accessor (scheme-slot scheme palette )
  `(progn
     (defgeneric ,scheme-slot (,scheme))
     (defmethod ,scheme-slot ((,scheme colorscheme))
       (slot-value ,palette (,(intern (concatenate 'string "-" (symbol-name scheme-slot))) ,scheme)))))


;; &group interfaces
;;; Palette class and methods &group

(defclass palette () ; solarized http://ethanschoonover.com/solarized
  ((base03     :accessor palette-base03      :initform "#002b36")
   (base02     :accessor palette-base02      :initform "#073642")
   (base01     :accessor palette-base01      :initform "#586e75")
   (base00     :accessor palette-base00      :initform "#657b83")
   (base0      :accessor palette-base0       :initform "#839496")
   (base1      :accessor palette-base1       :initform "#93a1a1")
   (base2      :accessor palette-base2       :initform "#eee8d5")
   (base3      :accessor palette-base3       :initform "#fdf6e3")
   (yellow     :accessor palette-yellow      :initform "#b58900")
   (orange     :accessor palette-orange      :initform "#cb4b16")
   (red        :accessor palette-red         :initform "#dc322f")
   (magenta    :accessor palette-magenta     :initform "#d33682")
   (violet     :accessor palette-violet      :initform "#6c71c4")
   (blue       :accessor palette-blue        :initform "#268bd2")
   (cyan       :accessor palette-cyan        :initform "#2aa198")
   (green      :accessor palette-green       :initform "#859900")))

(defgeneric invert-palette (palette))

;;; The palette var: this defaults to the solarized palette defined
;;; above, but can (and should) be temporarily rebound via the 
;;; with-palette macro below.
(defparameter *palette* (make-instance 'palette))

(defmacro let-palette (palette &body body)
  "Set custom palette in end-user code"
  `(let ((*palette* ,palette))
     ,@body))

(defmacro with-palette ((place) &body body)
  "Access the current palette"
  `(let ((,place *palette*))
     ,@body))

;;; &endgroup
;;; &group Color scheme
(defclass colorscheme ()
  ((bg           :accessor -colorscheme-bg           :initform 'base03)
   (bg-highlight :accessor -colorscheme-bg-highlight :initform 'base02)
   (fg-deemph    :accessor -colorscheme-fg-deemph    :initform 'base01)
   (fg           :accessor -colorscheme-fg           :initform 'base0 )
   (fg-highlight :accessor -colorscheme-fg-highlight :initform 'base1 )
   (hover-highlight :accessor -colorscheme-hover-highlight :initform 'base3 )
   (accent       :accessor -colorscheme-accent       :initform 'violet)))

(defgeneric accentize (colorscheme accent))

(def-palette-accessor colorscheme-bg               scheme *palette*)
(def-palette-accessor colorscheme-bg-highlight     scheme *palette*)
(def-palette-accessor colorscheme-fg-deemph        scheme *palette*)
(def-palette-accessor colorscheme-fg               scheme *palette*)
(def-palette-accessor colorscheme-fg-highlight     scheme *palette*)
(def-palette-accessor colorscheme-accent           scheme *palette*)
(def-palette-accessor colorscheme-hover-highlight  scheme *palette*)

;;; &endgroup
;; &endgroup

(defmethod invert-palette ((palette palette))
  (let ((result (make-instance 'palette)))
    (initialize-to result palette
      (palette-base03 palette-base3)
      (palette-base02 palette-base2)
      (palette-base01 palette-base1)
      (palette-base00 palette-base0)
      (palette-base0  palette-base00)
      (palette-base1  palette-base01)
      (palette-base2  palette-base02)
      (palette-base3  palette-base03))
    result))

(defmethod accentize ((colorscheme colorscheme) accent)
  (setf (colorscheme-accent colorscheme)
        (funcall accent colorscheme)))


(defun get-paths (tree)
  (labels ((get-paths-h (tree &optional tail history result)
             (cond ((null tree) (reverse result))
                   ((symbolp tree) (cons (cons tree history) (get-paths-h tail nil (cons tree history) result)))
                   ((listp tree) (cond ((symbolp (car tree)) (get-paths-h (car tree)
                                                                          (cdr tree)
                                                                          history
                                                                          result))
                                       ((listp (car tree))
                                        (append (get-paths-h (car tree) nil history)
                                                (get-paths-h (cdr tree)
                                                             nil
                                                             (cdr history)
                                                             result))))))))
    (mapcar (get-paths-h tree)))) ; Don't reverse: that'll be done by the user, as I'm appending to the tree

;;; Eventually this will help concision in themey stuff

;'(a '((:background . color1) (:color . color2))
;   (b '((:background . color3)))
;   ((c + d) ((:border . color1)))) ->

;(lass:compile-and-write
;  (list a
;        :background (color1 scheme)
;        :color (color2 scheme))
;  (list (a b) :background (color3 scheme))
;  (list (a b (c + d)) :border (color1 scheme)))

;(defmacro gen-css (scheme-v ,@body selectors)
;  (alexandria:with-gensyms (scheme)
;    (loop for ())
;    )

;  )
; vim: foldmethod=marker foldmarker=&group,&endgroup foldlevel=0 :