From 94d2fc1815a919734353c942f224db1de4b4fcb8 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Mon, 7 Mar 2011 09:04:49 +0100 Subject: Django, org * Added nxhtml, mostly for django support. * Changed some org settings. --- emacs.d/nxhtml/util/css-color.el | 983 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 983 insertions(+) create mode 100644 emacs.d/nxhtml/util/css-color.el (limited to 'emacs.d/nxhtml/util/css-color.el') diff --git a/emacs.d/nxhtml/util/css-color.el b/emacs.d/nxhtml/util/css-color.el new file mode 100644 index 0000000..38d400c --- /dev/null +++ b/emacs.d/nxhtml/util/css-color.el @@ -0,0 +1,983 @@ +;;; css-color.el --- Highlight and edit CSS colors + +(defconst css-color:version "0.03") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen +;; Keywords: processes, css, extensions, tools +;; Some smaller changes made by Lennart Borgman + +;; Last-Updated: 2009-10-19 Mon + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Edit css-colors in hex, rgb or hsl notation in-place, with +;; immediate feedback by font-locking. Cycle between color-spaces. + +;; Usage: + +;; (autoload 'css-color-mode "css-color" "" t) +;; (add-hook 'css-mode-hook 'css-color-mode-turn-on) + +;; Css-Css-color.el propertizes colours in a CSS stylesheet found by +;; font-locking code with a keymap. From that keymap, you can easily +;; adjust values such as red green and blue, hue, saturation and +;; value, or switch between different color (space) notations. + +;; It supports all 'css-colors', so hex, rgb(), hsl() and even HTML +;; color names (although I wouldn't use them myself, it is nice to be +;; able to quickly convert those), can be used and switched between. + +;; The rgb() notation can be expressed either in percentages or in +;; values between 0-255. + +;; You can cycle between the different formats (with SPACE), so that +;; it is possible to edit the color in hsl mode (which is more +;; intuitive than hsv, although hsv has its merits too), and switch +;; back to rgb or hex if so desired. + +;; With point on a color, the keys - and = to are bound to the down +;; and up functions for channels (or 'fields'). Toggling percentage +;; in rgb() is done with the % key (not sure if that is wise +;; though). The TAB key is bound to go to the next channel, cycling +;; when at the end. color.el propertizes the longhand hexcolours +;; found by the + +;; Caveats: + +;; Notation cycling can often introduce small errors inherent to +;; switching color spaces. Currently there is no check nor a warning +;; for that. + +;; ToDo: + +;; Try and fix those conversion inaccuracies. This cannot be done +;; completely I guess. But maybe we can check whether this has +;; occured, and then warn. + +;;; Change log: + +;; 2009-01-11 Lennart Borgman +;; - Minor code clean up. +;; 2009-05-23 Lennart Borgman +;; - Let bound m1 and m2. + +;;; Code: +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'mumamo nil t)) + +;;;###autoload +(defgroup css-color () + "Customization group for library `css-color'." + :group 'css + :group 'nxhtml) + +(defconst css-color-hex-chars "0123456789abcdefABCDEF" + "Composing chars in hexadecimal notation, save for the hash (#) sign.") + +(defconst css-color-hex-re + "#\\([a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)") + +(defconst css-color-hsl-re + "hsla?(\\([[:digit:]]\\{1,3\\}\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*\\)\\)%,[[:space:]]*\\([[:digit:]]\\{1,3\\}\\)\\(?:\.?[[:digit:]]*\\)%)") + +(defconst css-color-rgb-re + "rgba?(\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\)\\(:?,[[:space:]]*\\(0\.[0-9]+\\|1\\)\\)?)") + +(defconst css-color-html-colors + '(("AliceBlue" "#F0F8FF") + ("AntiqueWhite" "#FAEBD7") + ("Aqua" "#00FFFF") + ("Aquamarine" "#7FFFD4") + ("Azure" "#F0FFFF") + ("Beige" "#F5F5DC") + ("Bisque" "#FFE4C4") + ("Black" "#000000") + ("BlanchedAlmond" "#FFEBCD") + ("Blue" "#0000FF") + ("BlueViolet" "#8A2BE2") + ("Brown" "#A52A2A") + ("BurlyWood" "#DEB887") + ("CadetBlue" "#5F9EA0") + ("Chartreuse" "#7FFF00") + ("Chocolate" "#D2691E") + ("Coral" "#FF7F50") + ("CornflowerBlue" "#6495ED") + ("Cornsilk" "#FFF8DC") + ("Crimson" "#DC143C") + ("Cyan" "#00FFFF") + ("DarkBlue" "#00008B") + ("DarkCyan" "#008B8B") + ("DarkGoldenRod" "#B8860B") + ("DarkGray" "#A9A9A9") + ("DarkGrey" "#A9A9A9") + ("DarkGreen" "#006400") + ("DarkKhaki" "#BDB76B") + ("DarkMagenta" "#8B008B") + ("DarkOliveGreen" "#556B2F") + ("Darkorange" "#FF8C00") + ("DarkOrchid" "#9932CC") + ("DarkRed" "#8B0000") + ("DarkSalmon" "#E9967A") + ("DarkSeaGreen" "#8FBC8F") + ("DarkSlateBlue" "#483D8B") + ("DarkSlateGray" "#2F4F4F") + ("DarkSlateGrey" "#2F4F4F") + ("DarkTurquoise" "#00CED1") + ("DarkViolet" "#9400D3") + ("DeepPink" "#FF1493") + ("DeepSkyBlue" "#00BFFF") + ("DimGray" "#696969") + ("DimGrey" "#696969") + ("DodgerBlue" "#1E90FF") + ("FireBrick" "#B22222") + ("FloralWhite" "#FFFAF0") + ("ForestGreen" "#228B22") + ("Fuchsia" "#FF00FF") + ("Gainsboro" "#DCDCDC") + ("GhostWhite" "#F8F8FF") + ("Gold" "#FFD700") + ("GoldenRod" "#DAA520") + ("Gray" "#808080") + ("Grey" "#808080") + ("Green" "#008000") + ("GreenYellow" "#ADFF2F") + ("HoneyDew" "#F0FFF0") + ("HotPink" "#FF69B4") + ("IndianRed" "#CD5C5C") + ("Indigo" "#4B0082") + ("Ivory" "#FFFFF0") + ("Khaki" "#F0E68C") + ("Lavender" "#E6E6FA") + ("LavenderBlush" "#FFF0F5") + ("LawnGreen" "#7CFC00") + ("LemonChiffon" "#FFFACD") + ("LightBlue" "#ADD8E6") + ("LightCoral" "#F08080") + ("LightCyan" "#E0FFFF") + ("LightGoldenRodYellow" "#FAFAD2") + ("LightGray" "#D3D3D3") + ("LightGrey" "#D3D3D3") + ("LightGreen" "#90EE90") + ("LightPink" "#FFB6C1") + ("LightSalmon" "#FFA07A") + ("LightSeaGreen" "#20B2AA") + ("LightSkyBlue" "#87CEFA") + ("LightSlateGray" "#778899") + ("LightSlateGrey" "#778899") + ("LightSteelBlue" "#B0C4DE") + ("LightYellow" "#FFFFE0") + ("Lime" "#00FF00") + ("LimeGreen" "#32CD32") + ("Linen" "#FAF0E6") + ("Magenta" "#FF00FF") + ("Maroon" "#800000") + ("MediumAquaMarine" "#66CDAA") + ("MediumBlue" "#0000CD") + ("MediumOrchid" "#BA55D3") + ("MediumPurple" "#9370D8") + ("MediumSeaGreen" "#3CB371") + ("MediumSlateBlue" "#7B68EE") + ("MediumSpringGreen" "#00FA9A") + ("MediumTurquoise" "#48D1CC") + ("MediumVioletRed" "#C71585") + ("MidnightBlue" "#191970") + ("MintCream" "#F5FFFA") + ("MistyRose" "#FFE4E1") + ("Moccasin" "#FFE4B5") + ("NavajoWhite" "#FFDEAD") + ("Navy" "#000080") + ("OldLace" "#FDF5E6") + ("Olive" "#808000") + ("OliveDrab" "#6B8E23") + ("Orange" "#FFA500") + ("OrangeRed" "#FF4500") + ("Orchid" "#DA70D6") + ("PaleGoldenRod" "#EEE8AA") + ("PaleGreen" "#98FB98") + ("PaleTurquoise" "#AFEEEE") + ("PaleVioletRed" "#D87093") + ("PapayaWhip" "#FFEFD5") + ("PeachPuff" "#FFDAB9") + ("Peru" "#CD853F") + ("Pink" "#FFC0CB") + ("Plum" "#DDA0DD") + ("PowderBlue" "#B0E0E6") + ("Purple" "#800080") + ("Red" "#FF0000") + ("RosyBrown" "#BC8F8F") + ("RoyalBlue" "#4169E1") + ("SaddleBrown" "#8B4513") + ("Salmon" "#FA8072") + ("SandyBrown" "#F4A460") + ("SeaGreen" "#2E8B57") + ("SeaShell" "#FFF5EE") + ("Sienna" "#A0522D") + ("Silver" "#C0C0C0") + ("SkyBlue" "#87CEEB") + ("SlateBlue" "#6A5ACD") + ("SlateGray" "#708090") + ("SlateGrey" "#708090") + ("Snow" "#FFFAFA") + ("SpringGreen" "#00FF7F") + ("SteelBlue" "#4682B4") + ("Tan" "#D2B48C") + ("Teal" "#008080") + ("Thistle" "#D8BFD8") + ("Tomato" "#FF6347") + ("Turquoise" "#40E0D0") + ("Violet" "#EE82EE") + ("Wheat" "#F5DEB3") + ("White" "#FFFFFF") + ("WhiteSmoke" "#F5F5F5") + ("Yellow" "#FFFF00") + ("YellowGreen" "#9ACD32"))) + +(defvar css-color-html-re + (concat "\\<\\(" + (funcall 'regexp-opt + (mapcar 'car css-color-html-colors)) + "\\)\\>")) + +(defconst + css-color-color-re + "\\(?:#\\(?:[a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)\\|hsl(\\(?:[[:digit:]]\\{1,3\\}\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}\\)%,[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}\\)%)\\|rgba?(\\(?:[[:digit:]]\\{1,3\\}%?\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}%?\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}%?\\)\\(?:,[[:space:]]*\\(?:0.[0-9]+\\|1\\)\\)?)\\)" + "Regular expression containing only shy groups matching any type of CSS color") + +;; (defconst css-color-color-re +;; (concat "\\(?1:" +;; (mapconcat +;; 'identity +;; (list css-color-hex-re +;; css-color-hsl-re +;; css-color-rgb-re) "\\|") +;; "\\)")) + +(defvar css-color-keywords + `((,css-color-hex-re + (0 + (progn + (when (= 7 (- (match-end 0) + (match-beginning 0))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-map)) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'hex) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + (match-string-no-properties 0) + :foreground + (css-color-foreground-color + (match-string-no-properties 0))))))) + (,css-color-html-re + (0 + (let ((color + (css-color-string-name-to-hex (match-string-no-properties 0)))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'name) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))) + (,css-color-hsl-re + (0 + (let ((color (concat "#" (apply 'css-color-hsl-to-hex + (mapcar 'string-to-number + (list + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))))))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'hsl) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))) + (,css-color-rgb-re + (0 + (let ((color (css-color-string-rgb-to-hex (match-string-no-properties 0)))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'rgb) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))))) + + +;;;###autoload +(define-minor-mode css-color-mode + "Show hex color literals with the given color as background. +In this mode hexadecimal colour specifications like #6600ff are +displayed with the specified colour as background. + +Certain keys are bound to special colour editing commands when +point is at a hexadecimal colour: + +\\{css-color-map}" + :initial-value nil + :group 'css-color + (unless font-lock-defaults + (error "Can't use css-color-mode for this major mode")) + (if css-color-mode + (progn + (unless font-lock-mode (font-lock-mode 1)) + (css-color-font-lock-hook-fun) + (add-hook 'font-lock-mode-hook 'css-color-font-lock-hook-fun nil t)) + (remove-hook 'font-lock-mode-hook 'css-color-font-lock-hook-fun t) + (font-lock-remove-keywords nil css-color-keywords)) + ;;(font-lock-fontify-buffer) + (save-restriction + (widen) + (mumamo-mark-for-refontification (point-min) (point-max)))) + +(put 'css-color-mode 'permanent-local t) + +(defun css-color-turn-on-in-buffer () + "Turn on `css-color-mode' in `css-mode'." + (when (derived-mode-p 'css-mode) + (css-color-mode 1))) + +;;;###autoload +(define-globalized-minor-mode css-color-global-mode css-color-mode + css-color-turn-on-in-buffer + :group 'css-color) + +(defun css-color-font-lock-hook-fun () + "Add css-color pattern to font-lock's." + (if font-lock-mode + (font-lock-add-keywords nil css-color-keywords t) + (css-color-mode -1))) + +(defvar css-color-map + (let ((m (make-sparse-keymap "css-color"))) + (define-key m "=" 'css-color-up) + (define-key m "-" 'css-color-down) + (define-key m "h" 'css-color-hue-up) + (define-key m "H" 'css-color-hue-down) + (define-key m "s" 'css-color-saturation-up) + (define-key m "S" 'css-color-saturation-down) + (define-key m "v" 'css-color-value-up) + (define-key m "V" 'css-color-value-down) + (define-key m "\t" 'css-color-next-channel) + (define-key m " " 'css-color-cycle-type) + m) + "Mode map for `css-color-minor-mode'") + +(defvar css-color-generic-map + (let ((m (make-sparse-keymap "css-color"))) + (define-key m "=" 'css-color-num-up) + (define-key m "-" 'css-color-num-down) + (define-key m " " 'css-color-cycle-type) + (define-key m "%" 'css-color-toggle-percentage) + (define-key m "\t" 'css-color-next-channel) + m) + "Mode map for simple numbers in `css-color-minor-mode'") + +(defun css-color-pal-lumsig (r g b) + "Return PAL luminance signal, but in range 0-255." + (+ + (* 0.3 r) + (* 0.59 g) + (* 0.11 b))) + +(defun css-color-foreground-color (hex-color) + (multiple-value-bind (r g b) (css-color-hex-to-rgb hex-color) + (if (< (css-color-pal-lumsig r g b) 128) + "#fff" + "#000"))) + +;; Normalizing funs +(defun css-color-normalize-hue (h) + (mod (+ (mod h 360) 360) 360)) + +(defun css-color-within-bounds (num min max) + (min (max min num) max)) + +;; Source: hex +(defun css-color-hex-to-rgb (str) + (cond + ((not (string-match "^#?[a-fA-F[:digit:]]*$" str)) + (error "No valid hexadecimal: %s" str)) + ((= 0 (length str)) + nil) + ((= (aref str 0) 35) + (css-color-hex-to-rgb (substring str 1))) + (;;(oddp (length str)) + (= (mod (length str) 2) 1) + (css-color-hex-to-rgb (mapconcat (lambda (c) + (make-string 2 c)) + (string-to-list str) ""))) + (t (cons (string-to-number (substring str 0 2) 16) + (css-color-hex-to-rgb (substring str 2)))))) + +(defun css-color-hex-to-hsv (hex) + (multiple-value-bind (r g b) (css-color-hex-to-rgb hex) + (css-color-rgb-to-hsv r g b))) + +;; Source: rgb +(defun css-color-rgb-to-hex (r g b) + "Return r g b as #rrggbb in hexadecimal, propertized to have +the keymap `css-color-map'" + (format "%02x%02x%02x" r g b)) ;val + +(defun css-color-rgb-to-hsv (r g b) + "Return list of (hue saturation value). +Arguments are: R = red; G = green; B = blue. +Measure saturation and value on a scale from 0 - 100. +GIMP-style, that is." + (let* ((r (float r)) + (g (float g)) + (b (float b)) + (max (max r g b)) + (min (min r g b))) + (values + (round + (cond ((and (= r g) (= g b)) 0) + ((and (= r max) + (>= g b)) + (* 60 (/ (- g b) (- max min)))) + ((and (= r max) + (< g b)) + (+ 360 (* 60 (/ (- g b) (- max min))))) + ((= max g) + (+ 120 (* 60 (/ (- b r) (- max min))))) + ((= max b) + (+ 240 (* 60 (/ (- r g) (- max min))))))) ;hue + (round (* 100 (if (= max 0) 0 (- 1 (/ min max))))) ;sat + (round (/ max 2.55))))) + +(defun css-color-rgb-to-hsl (r g b) + "Return R G B (in range 0-255) converted to HSL (0-360 for hue, rest in %)" + (let* ((r (/ r 255.0)) + (g (/ g 255.0)) + (b (/ b 255.0)) + (h 0) + (s 0) + (l 0) + (v (max r g b)) + (m (min r g b)) + (l (/ (+ m v) 2.0)) + (vm 0) + (r2 0) + (g2 0) + (b2 0)) + (multiple-value-bind (h s v) + (if (<= l 0) + (values h s l) + (setq vm (- v m) + s vm) + (if (>= 0 s) + (values h s l) + (setq s (/ s (if (<= l 0.5) + (+ v m) + (- 2.0 v m)))) + (if (not (= 0 vm)) + (setq r2 (/ (- v r) vm) + g2 (/ (- v g) vm) + b2 (/ (- v b) vm))) + (cond ((= r v) + (setq h (if (= g m) + (+ 5.0 b2) + (- 1.0 g2)))) + ((= g v) + (setq h (if (= b m) + (+ 1.0 r2) + (- 3.0 b2)))) + (t + (setq h (if (= r m) + (+ 3.0 g2) + (- 5.0 r2))))) + (values (/ h 6.0) s l))) + (list (round(* 360 h)) + (* 100 s) + (* 100 l))))) + +;; Source: hsv +(defun css-color-hsv-to-hsl (h s v) + (multiple-value-bind (r g b) (css-color-hsv-to-rgb h s v) + (css-color-rgb-to-hsl r g b))) + +(defun css-color-hsv-to-hex (h s v) + (apply 'css-color-rgb-to-hex (css-color-hsv-to-rgb h s v))) + +(defun css-color-hsv-to-rgb (h s v) + "Convert a point in the Hue, Saturation, Value (aka Brightness) +color space to list of normalized Red, Green, Blue values. + +HUE is an angle in the range of 0 degrees inclusive to 360 +exclusive. The remainder of division by 360 is used for +out-of-range values. +SATURATION is in the range of 0 to 100. +VALUE is in the range of 0 to 100. +Returns a list of values in the range of 0 to 255. +" + ;; Coerce to float and get hue into range. + (setq h (mod h 360.0) + s (/ (float s) 100) + v (/ (float v) 100)) + (let* ((hi (floor h 60.0)) + (f (- (/ h 60.0) hi)) + (p (* v (- 1.0 s))) + (q (* v (- 1.0 (* f s)))) + ;; cannot use variable t, obviously. + (u (* v (- 1.0 (* (- 1.0 f) s)))) + r g b) + (case hi + (0 (setq r v g u b p)) + (1 (setq r q g v b p)) + (2 (setq r p g v b u)) + (3 (setq r p g q b v)) + (4 (setq r u g p b v)) + (5 (setq r v g p b q))) + (mapcar (lambda (color) (round (* 255 color))) (list r g b)))) + +(defun css-color-hsv-to-prop-hexstring (color-data) + (propertize + (apply 'css-color-hsv-to-hex color-data) + 'keymap css-color-map + 'css-color color-data)) + +;; Source: hsl +(defun css-color-hsl-to-rgb-fractions (h s l) + (let (m1 m2) + (if (<= l 0.5) + (setq m2 (* l (+ s 1))) + (setq m2 (- (+ l s) (* l s)))) + (setq m1 (- (* l 2) m2)) + (values (css-color-hue-to-rgb m1 m2 (+ h (/ 1 3.0))) + (css-color-hue-to-rgb m1 m2 h) + (css-color-hue-to-rgb m1 m2 (- h (/ 1 3.0)))))) + +(defun css-color-hsl-to-rgb (h s l) + (multiple-value-bind (r g b) + (css-color-hsl-to-rgb-fractions + (/ h;; (css-color-normalize-hue h) + 360.0) + (/ s 100.0) + (/ l 100.0)) + (values (css-color-within-bounds (* 256 r) 0 255) + (css-color-within-bounds (* 256 g) 0 255) + (css-color-within-bounds (* 256 b) 0 255)))) + +(defun css-color-hsl-to-hex (h s l) + (apply 'css-color-rgb-to-hex + (css-color-hsl-to-rgb h s l))) + +(defun css-color-hue-to-rgb (x y h) + (when (< h 0) (incf h)) + (when (> h 1) (decf h)) + (cond ((< h (/ 1 6.0)) + (+ x (* (- y x) h 6))) + ((< h 0.5) y) + ((< h (/ 2.0 3.0)) + (+ x (* (- y x) (- (/ 2.0 3.0) h) 6))) + (t x))) + +(defun css-color-parse-hsl (str) + (string-match + css-color-hsl-re + str) + (mapcar 'string-to-number + (list + (match-string 1 str) + (match-string 2 str) + (match-string 3 str)))) + +(defun css-color-inchue (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list (+ incr h) s v)))) + +(defun css-color-incsat (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list h (css-color-within-bounds (+ incr s) 0 100) v)))) + +(defun css-color-incval (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list h s (css-color-within-bounds (+ incr v) 0 100))))) + +(defun css-color-hexval-beginning () + (skip-chars-backward css-color-hex-chars) + (if (= (char-after) 35) + (forward-char 1))) + +(defun css-color-replcolor-at-p (fun increment) + (let ((pos (point))) + (css-color-hexval-beginning) + (insert + (funcall fun + (css-color-get-color-at-point) + increment)) + (delete-region (point) (+ (point) 6)) + (goto-char pos))) + +(defun css-color-get-color-at-point () + (save-excursion + (css-color-hexval-beginning) + (let ((saved-color (get-text-property (point) 'css-color))) + (or saved-color + (css-color-hex-to-hsv + (buffer-substring-no-properties (point) (+ (point) 6))))))) + +(defun css-color-adj-hue-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-inchue increment)) + +(defun css-color-adj-saturation-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-incsat increment)) + +(defun css-color-adj-value-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-incval increment)) + +(defun css-color-what-channel () + (let ((pos (point))) + (prog1 + (/ (skip-chars-backward css-color-hex-chars) -2) + (goto-char pos)))) + +(defun css-color-adjust-hex-at-p (incr) + (interactive "p") + (let ((pos (point)) + (channel (css-color-what-channel))) + (css-color-hexval-beginning) + (let ((rgb + (css-color-hex-to-rgb + (buffer-substring-no-properties (point) + (+ 6 (point)))))) + (setf (nth channel rgb) + (css-color-within-bounds + (+ incr (nth channel rgb)) + 0 255)) + (delete-region (point) (+ 6 (point))) + (insert + (propertize + (apply 'format "%02x%02x%02x" rgb) + 'keymap css-color-map + 'css-color nil + 'rear-nonsticky t))) + (goto-char pos))) + +;; channels (r, g, b) +(defun css-color-up (val) + "Adjust R/G/B up." + (interactive "p") + (css-color-adjust-hex-at-p val)) + +(defun css-color-down (val) + "Adjust R/G/B down." + (interactive "p") + (css-color-adjust-hex-at-p (- val))) +;; hue +(defun css-color-hue-up (val) + "Adjust Hue up." + (interactive "p") + (css-color-adj-hue-at-p val)) + +(defun css-color-hue-down (val) + "Adjust Hue down." + (interactive "p") + (css-color-adj-hue-at-p (- val))) +;; saturation +(defun css-color-saturation-up (val) + "Adjust Saturation up." + (interactive "p") + (css-color-adj-saturation-at-p val)) + +(defun css-color-saturation-down (val) + "Adjust Saturation down." + (interactive "p") + (css-color-adj-saturation-at-p (- val))) +;; value +(defun css-color-value-up (val) + "Adjust Value up." + (interactive "p") + (css-color-adj-value-at-p val)) + +(defun css-color-value-down (val) + "Adjust Value down." + (interactive "p") + (css-color-adj-value-at-p (- val))) + +(defun css-color-num-up (arg) + "Adjust HEX number up." + (interactive "p") + (save-excursion + (let ((digits "1234567890")) + (skip-chars-backward digits) + (when + (looking-at "[[:digit:]]+") + (replace-match + (propertize + (let ((num (+ (string-to-number (match-string 0)) arg))) + ;max = 100 when at percentage + (save-match-data + (cond ((looking-at "[[:digit:]]+%") + (setq num (min num 100))) + ((looking-back "hsla?(") + (setq num (css-color-normalize-hue num))) + ((memq 'css-color-type (text-properties-at (point))) + (setq num (min num 255))))) + (number-to-string num)) + 'keymap + css-color-generic-map)))))) + +(defun css-color-num-down (arg) + "Adjust HEX number down." + (interactive "p") + (save-excursion + (let ((digits "1234567890")) + (skip-chars-backward digits) + (when + (looking-at "[[:digit:]]+") + (replace-match + (propertize + (let ((num (- (string-to-number (match-string 0)) arg))) + ;max = 100 when at percentage + (save-match-data + (cond ((looking-back "hsla?(") + (setq num (css-color-normalize-hue num))) + (t (setq num (max 0 num))))) + (number-to-string num)) + 'keymap css-color-generic-map)))))) + + +(defun css-color-beginning-of-color () + "Skip to beginning of color. + +Return list of point and color-type." + (while (memq 'css-color-type (text-properties-at (point))) + (backward-char 1)) + (forward-char 1) + (cons (point) (plist-get (text-properties-at (point)) 'css-color-type))) + +(defun css-color-end-of-color () + "Skip to beginning of color. + +Return list of point and color-type." + (while (plist-get (text-properties-at (point)) 'css-color-type) + (forward-char 1)) + (cons (point) (plist-get (text-properties-at (1- (point))) 'css-color-type))) + +(defun css-color-color-info () + (destructuring-bind ((beg . type) + (end . type)) + (list + (css-color-beginning-of-color) + (css-color-end-of-color)) + (list beg end type (buffer-substring-no-properties beg end)))) + +(defconst css-color-type-circle '#1=(hex hsl rgb name . #1#)) + +(defun css-color-next-type (sym) + (cadr (member sym css-color-type-circle))) + +(defun css-color-cycle-type () + "Cycle color type." + (interactive) + (destructuring-bind (beg end type color) (css-color-color-info) + (if (or (= 0 (length color)) (null type)) + (error "Not at color")) + (delete-region beg end) + (insert + (propertize (funcall + (intern-soft (format "css-color-string-%s-to-%s" + type + (css-color-next-type type))) + color) + 'keymap (if (eq (css-color-next-type type) 'hex) + css-color-map + css-color-generic-map) 'rear-nonsticky t)) + (goto-char beg))) + +(defun css-color-string-hex-to-hsl (str) + (multiple-value-bind (h s l) + (apply 'css-color-rgb-to-hsl + (css-color-hex-to-rgb str)) + (format "hsl(%d,%d%%,%d%%)" + h s l))) + +(defun css-color-string-hsl-to-rgb (str) + (multiple-value-bind (h s l) + (css-color-parse-hsl str) + (apply 'format + "rgb(%d,%d,%d)" + (mapcar 'round (css-color-hsl-to-rgb h s l))))) + +(defun css-color-string-rgb-to-name (str) + (let ((color (css-color-string-rgb-to-hex str))) + (or (car (rassoc (list (upcase color)) css-color-html-colors)) ;if name ok + color))) ;else return hex + +(defun css-color-string-name-to-hex (str) + (let ((str (downcase str))) + (cadr (assoc-if + (lambda (a) + (string= + (downcase a) + str)) + css-color-html-colors)))) + +(defun css-color-string-rgb-to-hex (str) + (save-match-data + (string-match css-color-rgb-re str) + (concat "#" + (apply 'css-color-rgb-to-hex + (mapcar + ;;'string-to-number + (lambda (s) + (if (= (aref s (1- (length s))) ?\%) + (round (* (string-to-number s) 2.55)) + (string-to-number s))) + (list + (match-string-no-properties 1 str) + (match-string-no-properties 2 str) + (match-string-no-properties 3 str))))))) + +(defun css-color-string-hsl-to-hex (str) + (concat "#" (apply 'css-color-hsl-to-hex (css-color-parse-hsl str)))) + +(defun css-color-next-channel () + "Cycle color channel." + (interactive) + (multiple-value-bind (beg end type color) + (save-excursion (css-color-color-info)) + (case type + ((hsl rgb) + (if (not (re-search-forward ",\\|(" end t)) + (goto-char (+ beg 4)))) + (hex + (cond ((> (point) (- end 3)) + (goto-char (+ 1 beg))) + ((= (char-after) 35) + (forward-char 1)) + ((evenp (- (point) beg)) + (forward-char 1)) + (t (forward-char 2))))))) + +(defun css-color-hexify-anystring (str) + (cond ((string-match "^hsl" str) + (css-color-string-hsl-to-hex str)) + ((string-match "^rgb" str) + (css-color-string-rgb-to-hex str)) + (t str))) + +(defun css-color-toggle-percentage () + "Toggle percent ??" + (interactive) + (let ((pos (point))) + (if (eq (nth 2 (save-excursion (css-color-color-info))) 'rgb) + (let ((chars "%1234567890.")) + (skip-chars-backward chars) + (when + (looking-at "[[:digit:]]+\\(?:\.?[[:digit:]]*%\\)?%?") + (let ((s (match-string 0))) + (replace-match + (propertize + (if (= (aref s (1- (length s))) ?\%) + (number-to-string (round (* (string-to-number s) 2.55))) + (format "%d%%" (/ (string-to-number s) 2.55))) + 'keymap css-color-generic-map + 'rear-nonsticky t))) + ;;(goto-char pos) + )) + (message "No toggling at point.")))) + +;; provide some backwards-compatibility to hexcolor.el: +(defvar css-color-fg-history nil) +(defvar css-color-bg-history nil) + +;;;###autoload +(defun css-color-test (fg-color bg-color) + "Test colors interactively. +The colors are displayed in the echo area. You can specify the +colors as any viable css color. Example: + + red + #f00 + #0C0 + #b0ff00 + hsla(100, 50%, 25%) + rgb(255,100,120)" + (interactive (list (completing-read "Foreground color: " + css-color-html-colors + nil nil nil nil css-color-fg-history) + (completing-read "Background color: " + css-color-html-colors + nil nil nil nil css-color-bg-history))) + (let* ((s (concat " Foreground: " fg-color ", Background: " bg-color " "))) + (put-text-property 0 (length s) + 'face (list + :foreground (css-color-hexify-anystring fg-color) + :background (css-color-hexify-anystring bg-color)) + s) + (message "Here are the colors: %s" s))) + +(defun css-color-run-tests () + (interactive) + (unless + (progn + (assert + (string= (css-color-string-hex-to-hsl "#ffff00") "hsl(60,100%,50%)")) + (assert + (string= (css-color-string-rgb-to-hex "rgb(255, 50%, 0)")"#ff7f00")) + (assert + (string= (css-color-string-hsl-to-rgb "hsl(60, 100%, 50%)") "rgb(255,255,0)")) + (assert + (string= (css-color-string-hsl-to-hex "hsl(60, 100%, 50%)") "#ffff00"))) + (message "All tests passed"))) + +(provide 'css-color) +;;; css-color.el ends here -- cgit v1.2.3-54-g00ecf