git.fiddlerwoaroof.com
editor-color-theme.lisp
73122052
 ;;;; Copyright (C) 2013 Paulo Madeira
 ;;;;
 ;;;; This Source Code Form is subject to the terms of the Mozilla Public
 ;;;; License, v. 2.0. If a copy of the MPL was not distributed with this
 ;;;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 ;;; Interface
 
 (cl:in-package #:cl-user)
 
3c1c48ac
 
73122052
 (defpackage #:editor-color-theme
   (:use #:cl)
d437a024
   (:export #:*current-colors*
3c1c48ac
            #:all-color-themes
            #:color-theme-args
            #:color-theme
            #:define-color-theme
            #:remove-color-theme
            ))
73122052
 
 (in-package #:editor-color-theme)
 
 
 ;;; Configuration
 
3c1c48ac
 ;; Default foreground and background colors
 (defconstant +default-foreground-color+ :black)
 (defconstant +default-background-color+ :white)
73122052
 
d437a024
 (defvar *current-colors* (make-hash-table))
73122052
 
 ;;; Implementation
 
 (defvar *all-color-themes* (make-hash-table :test 'string=))
 
a8a8c7f6
 (defvar *editor-face-names*
   '(:region
     :show-point-face
     :interactive-input-face
     :highlight
     :non-focus-complete-face
     :font-lock-function-name-face
     :font-lock-comment-face
     :font-lock-type-face
     :font-lock-variable-name-face
     :font-lock-string-face
     :font-lock-keyword-face
     :font-lock-builtin-face
     :compiler-note-highlight
     :compiler-warning-highlight
     :compiler-error-highlight
     :incremental-search-face
     :incremental-search-other-matches-face
     ))
 
 
 
1a30967f
 (defclass editor-panes-theme ()
   ((editor-panes :initform nil :accessor editor-panes)
4f6ab34c
    (buffers-panes :initform nil :accessor buffers-panes)
8bab04e9
    (editor-background :initform +default-background-color+ :accessor bg)
4f6ab34c
    (editor-foreground :initform +default-foreground-color+ :accessor fg)
29b04c32
    (buffers-background :initform +default-background-color+ :accessor buffers-bg)
    (buffers-foreground :initform +default-foreground-color+ :accessor buffers-fg)
    (buffers-selected-foreground :initform +default-foreground-color+ :accessor buffers-selected-fg)))
1a30967f
 
 (defclass listener-panes-theme ()
172feac1
   ((listener-panes :initform nil :accessor listener-panes)
    (listener-foreground :initform +default-foreground-color+ :accessor bg)
    (listener-background :initform +default-background-color+ :accessor fg)))
1a30967f
 
 
 (defclass general-panes-theme ()
172feac1
   ((output-panes :initform nil :accessor output-panes)
    (output-foreground :initform +default-foreground-color+ :accessor output-fg)
    (output-background :initform +default-background-color+ :accessor output-bg)))
1a30967f
 
 (defvar *editor-tool* (make-instance 'editor-panes-theme))
 (defvar *listener-tool* (make-instance 'listener-panes-theme))
 (defvar *all-tools* (make-instance 'general-panes-theme))
a8a8c7f6
 
73122052
 (defun all-color-themes ()
   (maphash #'(lambda (key value)
3c1c48ac
                (declare (ignore value))
                key)
            *all-color-themes*))
73122052
 
 (defun color-theme-data (theme-name)
3c1c48ac
   (multiple-value-bind (data found?)
73122052
       (gethash theme-name *all-color-themes*)
     (if found?
3c1c48ac
         data
         (error "No color theme named ~s found." theme-name))))
73122052
 
 (defun color-theme-super-theme-names (theme-name)
   (first (color-theme-data theme-name)))
 
 (defun color-theme-args (theme-name)
   (rest (color-theme-data theme-name)))
 
29b04c32
 
 (defun buffers-color-function (lp symbol state)
   (declare (ignore lp))
   (cond ((eq state :normal)
          (buffers-fg *editor-tool*))
         ((eq state :selected)
          (buffers-selected-fg *editor-tool*))))
8bab04e9
 
a8a8c7f6
 (defun update-pane-colors (pane foreground background)
3c1c48ac
   (setf (capi:simple-pane-foreground pane) foreground)
   (setf (capi:simple-pane-background pane) background)
4f6ab34c
 
   (when (and (typep pane 'capi:editor-pane)
              (editor::buffer-font-lock-mode-p (capi:editor-pane-buffer pane)))
8bab04e9
     (gp:invalidate-rectangle pane)))
a9f0a320
 
 
 (defgeneric clear-colors (tool)
   (:documentation "Clear colors for tool keeping other data untouched"))
 
 (defgeneric update (tool)
   (:documentation "Update tool's colors"))
 
 
 (defmethod clear-colors ((self editor-panes-theme))
   (with-slots (editor-background editor-foreground) self
     (setf editor-background +default-background-color+)
     (setf editor-foreground +default-foreground-color+)))
 
 (defmethod clear-colors ((self listener-panes-theme))
   (with-slots (listener-background listener-foreground) self
     (setf listener-background +default-background-color+)
     (setf listener-foreground +default-foreground-color+)))
 
 (defmethod clear-colors ((self general-panes-theme))
   (with-slots (output-background output-foreground) self
     (setf output-background +default-background-color+)
     (setf output-foreground +default-foreground-color+)))
 
 
 (defmethod update ((self editor-panes-theme))
   (mapcar #'(lambda (pane)
               (update-pane-colors pane (fg self) (bg self)))
4f6ab34c
           (editor-panes self))
   (mapcar #'(lambda (pane)
               (update-pane-colors pane (buffers-fg self) (buffers-bg self)))
           (buffers-panes self)))
a9f0a320
 
 (defmethod update ((self listener-panes-theme))
   (mapcar #'(lambda (pane)
               (update-pane-colors pane (fg self) (bg self)))
           (listener-panes self)))
73122052
 
a9f0a320
 (defmethod update ((self general-panes-theme))
   (mapcar #'(lambda (pane)
               (update-pane-colors pane (output-fg self) (output-bg self)))
           (output-panes self)))
3c1c48ac
 
d437a024
 
73122052
 (defun set-color-theme (theme-name)
   (destructuring-bind (&rest color-theme-args
8bab04e9
                        &key foreground background
                          listener-foreground
                          listener-background
                          output-foreground
                          output-background
                          buffers-foreground
                          buffers-selected-foreground
                          buffers-background
                        &allow-other-keys)
73122052
       (color-theme-args theme-name)
3c1c48ac
 
a9f0a320
     ;; new instances of tools wrappers
     (clear-colors *editor-tool*)
     (clear-colors *listener-tool*)
     (clear-colors *all-tools*)
8bab04e9
 
3c1c48ac
     ;; editor foreground and background
172feac1
     (when foreground
       (setf (fg *editor-tool*) foreground))
     (when background
       (setf (bg *editor-tool*) background))
4bfaf1a7
     ;; listener foreground and background, uses
     ;; the :background and :foreground if not specified
172feac1
     (setf (fg *listener-tool*)
4bfaf1a7
           (or listener-foreground
172feac1
               (fg *editor-tool*))
           (bg *listener-tool*)
4bfaf1a7
           (or listener-background
172feac1
               (bg *editor-tool*)))
 
a8a8c7f6
     ;; output foreground and background, uses :background and
     ;; :foreground if not specified
172feac1
     (setf (output-fg *all-tools*)
a8a8c7f6
           (or output-foreground
172feac1
               (fg *editor-tool*))
           (output-bg *all-tools*)
a8a8c7f6
           (or output-background
172feac1
               (bg *editor-tool*)))
4f6ab34c
 
     ;; buffers list colors
     (setf (buffers-fg *editor-tool*)
           (or buffers-foreground
               (fg *editor-tool*))
29b04c32
           (buffers-selected-fg *editor-tool*)
           (or buffers-selected-foreground
               (buffers-fg *editor-tool*))
4f6ab34c
           (buffers-bg *editor-tool*)
           (or buffers-background
               (bg *editor-tool*)))
 
8bab04e9
 
73122052
     (dolist (name *editor-face-names*)
       (let* ((color-theme-args-for-face (getf color-theme-args name))
3c1c48ac
              (face-name (intern (string name) '#:editor))
              (face (editor:make-face face-name :if-exists t)))
8bab04e9
         (apply 'editor:make-face face-name
                :if-exists :overwrite
3c1c48ac
                :documentation (or (getf color-theme-args-for-face :documentation)
                                   (slot-value face 'documentation))
                color-theme-args-for-face))))
8bab04e9
 
73122052
   theme-name)
 
 (defun color-theme (theme-name)
   (mapc 'set-color-theme (color-theme-super-theme-names theme-name))
   (set-color-theme theme-name)
8bab04e9
 
a9f0a320
   (update *editor-tool*)
   (update *listener-tool*)
   (update *all-tools*)
8bab04e9
 
73122052
   theme-name)
 
 (defun define-color-theme (theme-name super-theme-names
3c1c48ac
                            &rest color-theme-args &key &allow-other-keys)
   (unless super-theme-names
     (setf super-theme-names '("default")))
73122052
   (dolist (super-theme-name super-theme-names)
     (multiple-value-bind (color-theme-data found?)
3c1c48ac
         (gethash super-theme-name *all-color-themes*)
73122052
       (declare (ignore color-theme-data))
       (unless found?
3c1c48ac
         (warn "Inherited color theme ~s not defined." super-theme-name))))
8bab04e9
 
73122052
   (setf (gethash theme-name *all-color-themes*) (list* super-theme-names color-theme-args))
8bab04e9
 
73122052
   theme-name)
 
 (defun remove-color-theme (theme-name)
   (remhash theme-name *all-color-themes*))
 
 (defun set-editor-pane-colors (pane)
   (typecase pane
     (capi:editor-pane
      (progn
1a30967f
        (pushnew pane (editor-panes *editor-tool*))
172feac1
        (let ((bg-color (bg *editor-tool*))
              (fg-color (fg *editor-tool*)))
          (setf (capi:simple-pane-foreground pane) fg-color)
          (setf (capi:simple-pane-background pane) bg-color))))))
73122052
 
a8a8c7f6
 
3c1c48ac
 (defun set-listener-pane-colors (pane)
   (typecase pane
     (capi:editor-pane
      (progn
1a30967f
        (pushnew pane (listener-panes *listener-tool*))
172feac1
        (let ((bg-color (bg *listener-tool*))
              (fg-color (fg *listener-tool*)))
          (setf (capi:simple-pane-foreground pane) fg-color)
          (setf (capi:simple-pane-background pane) bg-color))))))
3c1c48ac
 
 
a8a8c7f6
 (defun set-collector-pane-colors (pane)
172feac1
   ;;(when (typep (capi:top-level-interface pane) 'lw-tools:listener)
   (pushnew pane (output-panes *all-tools*))
   (let ((bg-color (output-bg *all-tools*))
         (fg-color (output-fg *all-tools*)))
     (setf (capi:simple-pane-foreground pane) fg-color)
     (setf (capi:simple-pane-background pane) bg-color)))
4f6ab34c
 
 (defun set-mulitcolumn-list-panel-colors (pane)
29b04c32
   (when (or (eq (capi:capi-object-name pane) 'lw-tools::buffers-list)
             (eq (capi:capi-object-name pane) 'lispworks-tools::narrow-buffers-list))
4f6ab34c
     (pushnew pane (buffers-panes *editor-tool*))
29b04c32
     (when (eq (capi:capi-object-name pane) 'lispworks-tools::narrow-buffers-list)
       (setf (slot-value pane 'capi::color-function) #'buffers-color-function))
4f6ab34c
     (update-pane-colors pane (buffers-fg *editor-tool*) (buffers-bg *editor-tool*))))
 
a8a8c7f6
 
73122052
 (lispworks:defadvice ((method capi:interface-display :before (lw-tools:editor))
                       change-editor-colors
                       :before
                       :documentation "Change editor colors.")
     (interface)
   (capi:map-pane-descendant-children interface 'set-editor-pane-colors))
 
 
3c1c48ac
 ;; we don't have defined capi:interface-display for lw-tools::listener,
 ;; so nothing to advice. Instead we need to define our own
 (sys::without-warning-on-redefinition
8bab04e9
     (defmethod capi:interface-display :before ((self lw-tools::listener))
       (capi:map-pane-descendant-children
        self 'set-listener-pane-colors)))
3c1c48ac
 
a8a8c7f6
 ;; capi:collector-pane does'nt have interface-display method called,
 ;; so we adding the :after constuctor instead
 (sys::without-warning-on-redefinition
   (defmethod initialize-instance :after ((self capi:collector-pane) &rest
                                          clos::initargs &key &allow-other-keys)
     (set-collector-pane-colors self)))
 
4f6ab34c
 (lispworks:defadvice ((method initialize-instance :after (capi:multi-column-list-panel))
                       change-multicolumn-colors
                       :after
                       :documentation "Change capi:multi-column-list-panel colors")
     (self &rest initargs &key &allow-other-keys)
576880b1
   (declare (ignore initargs))
4f6ab34c
   (set-mulitcolumn-list-panel-colors self))
 
 
3c1c48ac
 
73122052
 ;; This makes it "work" after the podium is launched
 (defun is-editor-pane-p (obj)
   (and (typep obj 'capi:editor-pane)
        (not (eq obj (hcl:class-prototype (class-of obj))))))
 
 (defun cache-existing-pane (pane)
1a30967f
   (pushnew pane (editor-panes *editor-tool*)))
73122052
 
 (defun cache-if-pane (obj)
   (when (is-editor-pane-p obj)
     (cache-existing-pane obj)))
 
 #+:lispworks-personal-edition
 (hcl:sweep-all-objects #'cache-if-pane)
 
 
 ;;; Initial color themes
 
 (define-color-theme "default" ()
   :foreground nil
   :background nil
   :region '(:foreground :color_highlighttext
3c1c48ac
             :background :color_highlight)
73122052
   :show-point-face '(:background :green)
   :interactive-input-face '(:foreground :red3)
   :highlight '(:bold-p t)
   :non-focus-complete-face '(:background :tweak_background)
   :font-lock-function-name-face '(:foreground :blue)
   :font-lock-comment-face '(:foreground :firebrick)
   :font-lock-type-face '(:foreground :forestgreen)
   :font-lock-variable-name-face '(:foreground :darkgoldenrod)
   :font-lock-string-face '(:foreground :rosybrown)
   :font-lock-keyword-face '(:foreground :purple)
   :font-lock-builtin-face '(:foreground :orchid)
   :compiler-note-highlight '(:foreground :magenta)
   :compiler-warning-highlight '(:foreground :orange3)
   :compiler-error-highlight '(:foreground :red)
   :incremental-search-face '(:background :tweak_background)
   :incremental-search-other-matches-face '(:underline-p t))
 
 (define-color-theme "plain" ()
   :foreground nil :background nil
   :region '(:foreground :color_highlighttext
3c1c48ac
             :background :color_highlight)
73122052
   :show-point-face '()
   :interactive-input-face '()
   :highlight '(:bold-p t)
   :non-focus-complete-face '(:background :tweak_background)
   :font-lock-function-name-face '()
   :font-lock-comment-face '()
   :font-lock-type-face '()
   :font-lock-variable-name-face '()
   :font-lock-string-face '()
   :font-lock-keyword-face '()
   :font-lock-builtin-face '()
   :compiler-note-highlight '()
   :compiler-warning-highlight '()
   :compiler-error-highlight '()
   :incremental-search-face '(:background :tweak_background)
   :incremental-search-other-matches-face '(:underline-p t))
 
 
 (define-color-theme "emacs" ()
3c1c48ac
   ;; :foreground nil :background nil
73122052
   :region '(:foreground :color_highlighttext
3c1c48ac
             :background :color_highlight)
73122052
   :show-point-face '(:background :green)
   :interactive-input-face '(:foreground :red3)
   :highlight '(:bold-p t)
   :non-focus-complete-face '(:background :tweak_background)
   :font-lock-function-name-face '(:foreground :blue)
   :font-lock-comment-face '(:foreground :gray40)
   :font-lock-type-face '(:foreground :forestgreen)
   :font-lock-variable-name-face '(:foreground :darkgoldenrod)
   :font-lock-string-face '(:foreground :rosybrown)
   :font-lock-keyword-face '(:foreground :purple)
   :font-lock-builtin-face '(:foreground :orchid)
   :compiler-note-highlight '(:foreground :magenta)
   :compiler-warning-highlight '(:foreground :orange3)
   :compiler-error-highlight '(:foreground :red)
   :incremental-search-face '(:background :tweak_background)
   :incremental-search-other-matches-face '(:underline-p t))
 
 
 (define-color-theme "torte" ()
   :foreground (color:make-rgb 0.8s0 0.8s0 0.8s0)
   :background (color:make-rgb 0.0s0 0.0s0 0.0s0)
   :region '(:foreground :color_highlighttext
3c1c48ac
             :background :color_highlight)
73122052
   :show-point-face `(:background ,(color:make-rgb 0.6275s0 0.1255s0 0.9412s0))
   :interactive-input-face '(:foreground :pink)
   :highlight '(:bold-p t)
   :non-focus-complete-face '(:background :tweak_background)
   :font-lock-function-name-face `(:foreground ,(color:make-rgb 0.0s0 1.0s0 1.0s0))
   :font-lock-comment-face `(:foreground ,(color:make-rgb 0.5s0 0.6275s0 1.0s0))
   :font-lock-type-face `(:foreground ,(color:make-rgb 0.5s0 1.0s0 0.5s0))
   :font-lock-variable-name-face `(:foreground ,(color:make-rgb 1.0s0 1.0s0 1.0s0))
   :font-lock-string-face `(:foreground ,(color:make-rgb 1.0s0 0.6275s0 0.6275s0))
   :font-lock-keyword-face `(:foreground ,(color:make-rgb 1.0s0 1.0s0 0.0s0))
   :font-lock-builtin-face `(:foreground ,(color:make-rgb 1.0s0 1.0s0 0.0s0))
   :compiler-note-highlight '(:foreground :magenta)
   :compiler-warning-highlight '(:foreground :orange)
   :compiler-error-highlight '(:foreground :red)
   :incremental-search-face '(:background :tweak_background)
   :incremental-search-other-matches-face '(:underline-p t))
 
 
9c06f674
 (defun make-rgb (red green blue &optional alpha)
   (color:make-rgb (/ red 255s0)
                   (/ green 255s0)
                   (/ blue 255s0)
                   (and alpha (/ alpha 255s0))))
 
 (defvar *solarized-color-table*
   '(:solarized-base03  (#x00 #x2b #x36)
     :solarized-base02  (#x07 #x36 #x42)
     :solarized-base01  (#x58 #x6e #x75)
     :solarized-base00  (#x65 #x7b #x83)
     :solarized-base0   (#x83 #x94 #x96)
     :solarized-base1   (#x93 #xa1 #xa1)
     :solarized-base2   (#xee #xe8 #xd5)
     :solarized-base3   (#xfd #xf6 #xe3)
     :solarized-yellow  (#xb5 #x89 #x00)
     :solarized-orange  (#xcb #x4b #x16)
     :solarized-red     (#xdc #x32 #x2f)
     :solarized-magenta (#xd3 #x36 #x82)
     :solarized-violet  (#x6c #x71 #xc4)
     :solarized-blue    (#x26 #x8b #xd2)
     :solarized-cyan    (#x2a #xa1 #x98)
     :solarized-green   (#x85 #x99 #x00)))
 
 (loop for list on *solarized-color-table* by #'cddr
       for name = (first list)
       for rgb = (second list)
       do
          (color:define-color-alias
              name
              (apply #'make-rgb rgb)))
 
 (define-color-theme "solarized-light" ()
   :foreground :solarized-base00
   :background :solarized-base3
   :region '(:foreground :solarized-base1
             :background :solarized-base3
             :inverse-p t)
   :highlight '(:background :solarized-base2)
   :font-lock-function-name-face '(:foreground :solarized-blue)
   :font-lock-comment-face '(:foreground :solarized-base1 :italic-p t)
   :font-lock-type-face '(:foreground :solarized-yellow)
   :font-lock-variable-name-face '(:foreground :solarized-blue)
   :font-lock-string-face '(:foreground :solarized-cyan)
   :font-lock-keyword-face '(:foreground :solarized-green)
   :font-lock-builtin-face '(:foreground :solarized-green)
   :compiler-note-highlight '(:foreground :solarized-green
                              :bold-p t)
   :compiler-warning-highlight '(:foreground :solarized-orange
                                 :bold-p t)
   :compiler-error-highlight '(:foreground :solarized-red
                               :inverse-p t)
   :show-point-face '(:foreground :solarized-cyan
                      :bold-p t :inverse-p t)
   :interactive-input-face '(:foreground :solarized-red)
   :non-focus-complete-face '(:background :solarized-base3)
   :parenthesis-font-face-colours '(:solarized-red
                                    :solarized-base01
                                    :solarized-green
                                    :solarized-orange
                                    :solarized-blue
                                    :solarized-magenta))
 
 (define-color-theme "solarized-dark" ()
   :foreground :solarized-base0
   :background :solarized-base03
   :region '(:foreground :solarized-base01
             :background :solarized-base03
             :inverse-p t)
   :highlight '(:background :solarized-base02)
   :font-lock-function-name-face '(:foreground :solarized-blue)
   :font-lock-comment-face '(:foreground :solarized-base01 :italic-p t)
   :font-lock-type-face '(:foreground :solarized-yellow)
   :font-lock-variable-name-face '(:foreground :solarized-blue)
   :font-lock-string-face '(:foreground :solarized-cyan)
   :font-lock-keyword-face '(:foreground :solarized-green)
   :font-lock-builtin-face '(:foreground :solarized-green)
   :compiler-note-highlight '(:foreground :solarized-green
                              :bold-p t)
   :compiler-warning-highlight '(:foreground :solarized-orange
                                 :bold-p t)
   :compiler-error-highlight '(:foreground :solarized-red
                               :inverse-p t)
   :show-point-face '(:foreground :solarized-cyan
                      :bold-p t :inverse-p t)
   :interactive-input-face '(:foreground :solarized-red)
   :non-focus-complete-face '(:background :solarized-base03)
   :parenthesis-font-face-colours '(:solarized-red
                                    :solarized-base1
                                    :solarized-green
                                    :solarized-orange
                                    :solarized-blue
                                    :solarized-magenta))
73122052
 
 ;;; Show presence when loaded
 (pushnew :editor-color-theme *features*)