make-color.el 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. ;;; make-color.el --- Alternative to picking color - update fg/bg color by pressing r/g/b/... keys
  2. ;; Copyright (C) 2014 Alex Kost
  3. ;; Author: Alex Kost <alezost@gmail.com>
  4. ;; Created: 9 Jan 2014
  5. ;; Version: 0.4.1
  6. ;; URL: https://github.com/alezost/make-color.el
  7. ;; Keywords: color
  8. ;; This program is free software; you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; This program is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; This package allows to find a color by pressing keys for smooth
  20. ;; changing foreground/background color of any text sample.
  21. ;; To manually install the package, copy this file to a directory from
  22. ;; `load-path' and add the following to your init-file:
  23. ;;
  24. ;; (autoload 'make-color "make-color" nil t)
  25. ;; (autoload 'make-color-switch-to-buffer "make-color" nil t)
  26. ;; Usage: select any region and call "M-x make-color". You will see a
  27. ;; buffer in `make-color-mode'. Select some text in it and press "n" to
  28. ;; set this text for colorizing. Now you can modify a color with the
  29. ;; following keys:
  30. ;;
  31. ;; - r/R, g/G, b/B - decrease/increase red, green, blue components
  32. ;; - c/C, m/M, y/Y - decrease/increase cyan, magenta, yellow components
  33. ;; - h/H, s/S, l/L - decrease/increase hue, saturation, luminance
  34. ;; - RET - change current color (prompt for a value)
  35. ;; If you are satisfied with current color, press "k" to put the color
  36. ;; into `kill-ring'. At any time you can set a new probing region with
  37. ;; "n". You can navigate through a history of probing regions with
  38. ;; "SPC", "N" and "P". If you forgot where the current probing region
  39. ;; is placed, press "SPC". Also you can switch between modifying
  40. ;; background/foreground colors with "t". See mode description ("C-h
  41. ;; m") for other key bindings.
  42. ;; Buffer in `make-color-mode' is not read-only, so you can yank and
  43. ;; delete text and undo the changes as you always do.
  44. ;; For full description, see <https://github.com/alezost/make-color.el>.
  45. ;;; Code:
  46. (require 'color)
  47. (require 'cl-macs)
  48. (defgroup make-color nil
  49. "Find suitable color by modifying a text sample."
  50. :group 'faces)
  51. (defcustom make-color-shift-step 0.02
  52. "Step of shifting a component of the current color.
  53. Should be a floating number from 0.0 to 1.0."
  54. :type 'float
  55. :group 'make-color)
  56. (defcustom make-color-sample
  57. "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet
  58. consectetur adipisci velit.
  59. Marcus Tullius Cicero"
  60. "Default text sample used for probing a color.
  61. See also `make-color-sample-beg' and `make-color-sample-end'."
  62. :type 'string
  63. :group 'make-color)
  64. (defcustom make-color-sample-beg 133
  65. "Start position of text in `make-color-sample' for probing a color.
  66. If nil, start probing text from the beginning of the sample."
  67. :type '(choice integer (const nil))
  68. :group 'make-color)
  69. (defcustom make-color-sample-end 154
  70. "End position of text in `make-color-sample' for probing a color.
  71. If nil, end probing text in the end of the sample."
  72. :type '(choice integer (const nil))
  73. :group 'make-color)
  74. (defcustom make-color-buffer-name "*Make Color*"
  75. "Default name of the make-color buffer."
  76. :type 'string
  77. :group 'make-color)
  78. (defcustom make-color-use-single-buffer t
  79. "If nil, create a new make-color buffer for each `make-color' call.
  80. If non-nil, use only one make-color buffer."
  81. :type 'boolean
  82. :group 'make-color)
  83. (defcustom make-color-use-whole-sample nil
  84. "If non-nil, use the whole sample text after \\[make-color].
  85. If nil, prompt for that after calling `make-color' on a selected text."
  86. :type 'boolean
  87. :group 'make-color)
  88. (defcustom make-color-show-color t
  89. "If non-nil, show message in minibuffer after changing current color."
  90. :type 'boolean
  91. :group 'make-color)
  92. (defcustom make-color-face-keyword :foreground
  93. "Default face parameter for colorizing."
  94. :type '(choice
  95. (const :tag "Foreground" :foreground)
  96. (const :tag "Background" :background))
  97. :group 'make-color)
  98. (defcustom make-color-new-color-after-region-change t
  99. "What color should be used after changing the probing region.
  100. If nil, current color stays the same.
  101. If non-nil, current color is set to the color of the probing region."
  102. :type 'boolean
  103. :group 'make-color)
  104. (defcustom make-color-get-color-function
  105. 'make-color-get-color-at-pos
  106. "Function used for getting a color of a character.
  107. Should accept 2 arguments: a symbol or keyword
  108. `foreground'/`background' and a point position."
  109. :type 'function
  110. :group 'make-color)
  111. (defcustom make-color-set-color-function
  112. 'make-color-set-color
  113. "Function used for setting a color of a region.
  114. Should accept 4 arguments:
  115. - symbol or keyword `foreground'/`background',
  116. - color - a list (R G B) of float numbers from 0.0 to 1.0,
  117. - position of the beginning of region,
  118. - position of the end of region."
  119. :type 'function
  120. :group 'make-color)
  121. (defvar make-color-mode-map
  122. (let ((map (make-sparse-keymap)))
  123. (define-key map "\C-j" 'newline)
  124. (define-key map "\C-m" 'make-color-set-current-color)
  125. (define-key map "n" 'make-color-set-probing-region)
  126. (define-key map "p" 'make-color-set-step)
  127. (define-key map "f" 'make-color-use-foreground)
  128. (define-key map "d" 'make-color-use-background)
  129. (define-key map "t" 'make-color-toggle-face-parameter)
  130. (define-key map "k" 'make-color-current-color-to-kill-ring)
  131. (define-key map "F" 'make-color-foreground-color-to-kill-ring)
  132. (define-key map "D" 'make-color-background-color-to-kill-ring)
  133. (define-key map " " 'make-color-goto-region)
  134. (define-key map "N" 'make-color-next-region)
  135. (define-key map "P" 'make-color-previous-region)
  136. (define-key map "u" 'undo)
  137. (define-key map "q" 'bury-buffer)
  138. map)
  139. "Keymap containing make-color commands.")
  140. ;;; Changing colors
  141. (defun make-color-+ (nums &optional overlap)
  142. "Return sum of float numbers from 0.0 to 1.0 from NUMS list.
  143. Returning value is always between 0.0 and 1.0 inclusive.
  144. If OVERLAP is non-nil and the sum exceeds the limits, oh god i
  145. can't formulate it, look at the code."
  146. (let ((res (apply #'+ nums)))
  147. (if overlap
  148. (let ((frac (- res (truncate res))))
  149. (if (> frac 0)
  150. frac
  151. (+ 1 frac)))
  152. (color-clamp res))))
  153. (cl-defun make-color-shift-color-by-rgb
  154. (color &key (red 0) (green 0) (blue 0))
  155. "Return RGB color by modifying COLOR with RED/GREEN/BLUE.
  156. COLOR and returning value are lists in a form (R G B).
  157. RED/GREEN/BLUE are numbers from 0.0 to 1.0."
  158. (list (make-color-+ (list (car color) red))
  159. (make-color-+ (list (cadr color) green))
  160. (make-color-+ (list (cl-caddr color) blue))))
  161. (cl-defun make-color-shift-color-by-hsl
  162. (color &key (hue 0) (saturation 0) (luminance 0))
  163. "Return RGB color by modifying COLOR with HUE/SATURATION/LUMINANCE.
  164. COLOR and returning value are lists in a form (R G B).
  165. HUE/SATURATION/LUMINANCE are numbers from 0.0 to 1.0."
  166. (let ((hsl (apply 'color-rgb-to-hsl color)))
  167. (color-hsl-to-rgb
  168. (make-color-+ (list (car hsl) hue) 'overlap)
  169. (make-color-+ (list (cadr hsl) saturation))
  170. (make-color-+ (list (cl-caddr hsl) luminance)))))
  171. ;;; Shifting current color
  172. (defvar make-color-current-color nil
  173. "Current color - a list in a form (R G B).")
  174. (defmacro make-color-define-shift-function
  175. (name direction sign-fun color-fun key &rest components)
  176. "Define function for shifting current color.
  177. Function name is `make-color-DIRECTION-NAME'.
  178. NAME is a unique part of function name like \"red\" or \"hue\".
  179. Can be a string or a symbol.
  180. DIRECTION is a string used in the name and
  181. description (\"increase\" or \"decrease\").
  182. SIGN-FUN is a function used for direction of shifting (`+' or `-').
  183. COLOR-FUN is a function used for modifying current color
  184. \(`make-color-shift-color-by-rgb' or
  185. `make-color-shift-color-by-hsl').
  186. If KEY is non-nil, a binding with KEY will be defined in
  187. `make-color-mode-map'.
  188. Each component from COMPONENTS list is one of the keywords
  189. accepted by COLOR-FUN. Specified COMPONENTS of the current color
  190. will be shifted by the defined function."
  191. (let* ((fun-name (intern (format "make-color-%s-%s" direction name)))
  192. (fun-doc (concat (format "%s %s component of the current color by VAL."
  193. (capitalize direction) name)
  194. "\nIf VAL is nil, use `make-color-shift-step'."))
  195. (fun-def
  196. `(defun ,fun-name (&optional val)
  197. ,fun-doc
  198. (interactive)
  199. (let ((color
  200. (apply ,color-fun
  201. (or make-color-current-color '(0 0 0))
  202. (cl-mapcan
  203. (lambda (elt)
  204. (list elt
  205. (if val
  206. (funcall ,sign-fun val)
  207. (funcall ,sign-fun make-color-shift-step))))
  208. ',components))))
  209. (make-color-update-sample color)))))
  210. (if key
  211. `(progn ,fun-def (define-key make-color-mode-map ,key ',fun-name))
  212. fun-def)))
  213. (defmacro make-color-define-shift-functions (model name key &rest components)
  214. "Define functions for increasing/decreasing current color.
  215. Define 2 functions: `make-color-increase-NAME' and
  216. `make-color-decrease-NAME' with optional argument VAL.
  217. MODEL is a string \"rgb\" or \"hsl\" for choosing
  218. `make-color-shift-color-by-rgb' or `make-color-shift-color-by-hsl'.
  219. KEY should be nil or a string of one letter. If KEY is non-nil,
  220. bindings for defined functions will be defined in
  221. `make-color-mode-map'. Up-case letter will be used for increasing
  222. function, down-case letter - for decreasing function.
  223. For other args, see `make-color-define-shift-function'."
  224. (let ((shift-fun (intern (concat "make-color-shift-color-by-" model))))
  225. `(progn
  226. (make-color-define-shift-function
  227. ,name "increase" #'+ #',shift-fun ,(upcase key) ,@components)
  228. (make-color-define-shift-function
  229. ,name "decrease" #'- #',shift-fun ,(downcase key) ,@components))))
  230. (make-color-define-shift-functions "rgb" "red" "r" :red)
  231. (make-color-define-shift-functions "rgb" "green" "g" :green)
  232. (make-color-define-shift-functions "rgb" "blue" "b" :blue)
  233. (make-color-define-shift-functions "rgb" "cyan" "c" :green :blue)
  234. (make-color-define-shift-functions "rgb" "magenta" "m" :blue :red)
  235. (make-color-define-shift-functions "rgb" "yellow" "y" :red :green)
  236. (make-color-define-shift-functions "hsl" "hue" "h" :hue)
  237. (make-color-define-shift-functions "hsl" "saturation" "s" :saturation)
  238. (make-color-define-shift-functions "hsl" "luminance" "l" :luminance)
  239. ;;; MakeColor buffers
  240. ;;;###autoload
  241. (defun make-color-switch-to-buffer (&optional arg)
  242. "Switch to make-color buffer or create one if needed.
  243. With prefix (if ARG is non-nil), make a new make-color buffer."
  244. (interactive "P")
  245. (let ((bufs (make-color-get-buffers))
  246. buf)
  247. (if (or arg (null bufs))
  248. (let (make-color-use-single-buffer)
  249. (make-color))
  250. ;; delete current make-color buffer from `bufs'
  251. (when (eq major-mode 'make-color-mode)
  252. (setq bufs (delete (current-buffer) bufs)))
  253. (cond
  254. ((null bufs)
  255. (message "This is a single make-color buffer."))
  256. ((null (cdr bufs)) ; there is only one non-current buffer
  257. (setq buf (car bufs)))
  258. (t
  259. (setq buf (completing-read "MakeColor buffer: "
  260. (mapcar #'buffer-name bufs)
  261. nil t))))
  262. (when buf
  263. (let ((win (get-buffer-window buf)))
  264. (if win
  265. (select-window win)
  266. (pop-to-buffer-same-window (get-buffer buf))))))))
  267. (defun make-color-get-buffers ()
  268. "Return a list of make-color buffers."
  269. (let ((re (regexp-quote make-color-buffer-name)))
  270. (cl-remove-if-not
  271. (lambda (buf) (string-match re (buffer-name buf)))
  272. (buffer-list))))
  273. (defun make-color-get-buffer (&optional clear unique)
  274. "Return make-color buffer.
  275. The name of the buffer is defined by `make-color-buffer-name'.
  276. If CLEAR is non-nil, delete the contents of the buffer.
  277. If UNIQUE is non-nil, create a unique buffer."
  278. (let ((buf (get-buffer-create
  279. (if unique
  280. (generate-new-buffer-name make-color-buffer-name)
  281. make-color-buffer-name))))
  282. (when clear
  283. (with-current-buffer buf (erase-buffer)))
  284. buf))
  285. ;;; Getting and setting faces
  286. ;; Original `foreground-color-at-point' and `background-color-at-point'
  287. ;; don't understand faces with property lists of face attributes (see
  288. ;; (info "(elisp) Special Properties")). For example, if a face was set
  289. ;; by `facemenu-set-foreground'/`facemenu-set-background' the original
  290. ;; functions return nil, so we need some code for getting a color.
  291. (defun make-color-set-color (param color beg end)
  292. "Set color of the text between BEG and END.
  293. PARAM is a symbol or keyword `foreground' or `background'.
  294. COLOR should be a list in a form (R G B)."
  295. (facemenu-add-face (list (list (make-color-keyword param) color))
  296. beg end))
  297. (defun make-color-get-color-from-face-spec (param spec)
  298. "Return color from face specification SPEC.
  299. PARAM is a keyword `:foreground' or `:background'.
  300. SPEC can be a face name, a property list of face attributes or a
  301. list of any level of nesting containing face names or property
  302. lists.
  303. Returning value is a string: either a color name or a hex value.
  304. If PARAM is not found in SPEC, return nil."
  305. (cond
  306. ((facep spec)
  307. (face-attribute-specified-or (face-attribute spec param nil t)
  308. nil))
  309. ((listp spec)
  310. (if (keywordp (car spec))
  311. (plist-get spec param)
  312. (let (res)
  313. (cl-loop for elt in spec
  314. do (setq res (make-color-get-color-from-face-spec
  315. param elt))
  316. until res)
  317. res)))
  318. (t
  319. (message "Ignoring unknown face specification '%s'." spec)
  320. nil)))
  321. (defun make-color-get-color-at-pos (param &optional pos)
  322. "Return color of a character at position POS.
  323. PARAM is a symbol or keyword `foreground' or `background'.
  324. If POS is not specified, use current point positiion."
  325. (let ((param (make-color-keyword param))
  326. (faceprop (get-text-property (or pos (point)) 'face)))
  327. (or (and faceprop
  328. (make-color-get-color-from-face-spec param faceprop))
  329. ;; if color was not found, use default face
  330. (face-attribute 'default param))))
  331. (defun make-color-foreground-color-at-point ()
  332. "Return foreground color of the character at point."
  333. (make-color-get-color-at-pos :foreground (point)))
  334. (defun make-color-background-color-at-point ()
  335. "Return background color of the character at point."
  336. (make-color-get-color-at-pos :background (point)))
  337. ;;; Probing regions
  338. (defcustom make-color-region-ring-size 20
  339. "Maximum number of stored regions."
  340. :type 'integer
  341. :group 'make-color)
  342. (defvar make-color-region-ring nil
  343. "List of stored regions.
  344. Each element is an overlay.")
  345. (defvar make-color-current-region-index 0
  346. "Index of the current element in `make-color-region-ring'.")
  347. (defun make-color-calc-index (&optional base shift)
  348. "Return index of a region from `make-color-region-ring'.
  349. Index of the returned element is a sum of BASE and SHIFT.
  350. If the sum exceeds the limits of `make-color-region-ring', overlap.
  351. If BASE is nil, use `make-color-current-region-index'.
  352. If SHIFT is nil, use 0."
  353. (if make-color-region-ring
  354. (mod (+ (or base make-color-current-region-index)
  355. (or shift 0))
  356. (length make-color-region-ring))
  357. 0))
  358. (defun make-color-save-region (beg end)
  359. "Make overlay and save it in `make-color-region-ring'.
  360. BEG and END are point positions for the overlay.
  361. Limit the size of `make-color-region-ring' to
  362. `make-color-region-ring-size'.
  363. Return index of the saved region."
  364. (when (>= (length make-color-region-ring)
  365. make-color-region-ring-size)
  366. (delete-overlay (car make-color-region-ring))
  367. (setq make-color-region-ring (cdr make-color-region-ring)))
  368. (setq make-color-region-ring
  369. (append make-color-region-ring (list (make-overlay beg end))))
  370. (- (length make-color-region-ring) 1))
  371. (defun make-color-get-region (&optional index)
  372. "Return cons cell of start and end positions of a probing region.
  373. INDEX is a number of region in `make-color-region-ring' (counting
  374. from 0). If nil, use `make-color-current-region-index'.
  375. Return nil, if there is no element with INDEX."
  376. (let ((overlay (nth index make-color-region-ring)))
  377. (when (and (overlayp overlay) (overlay-buffer overlay))
  378. (cons (overlay-start overlay)
  379. (overlay-end overlay)))))
  380. (defun make-color-set-region-as-current (index)
  381. "Set region number INDEX from `make-color-region-ring' as current."
  382. (setq make-color-current-region-index index))
  383. (defun make-color-get-probing-region-bounds ()
  384. "Return cons cell of start and end positions of a probing region.
  385. Return nil if probing region is not defined."
  386. (make-color-get-region
  387. make-color-current-region-index))
  388. (defun make-color-set-probing-region (&optional beg end force)
  389. "Use region between BEG and END for colorizing.
  390. If BEG or END is nil, use current region. If there is no active
  391. region and FORCE is non-nil, use the whole buffer."
  392. (interactive)
  393. (when (or (null beg) (null end))
  394. (if (region-active-p)
  395. (progn (setq beg (region-beginning)
  396. end (region-end))
  397. (deactivate-mark)
  398. (message "The region was set for color probing."))
  399. (if (or force
  400. (y-or-n-p "No active region. Use the whole sample for colorizing?"))
  401. (setq beg (point-min)
  402. end (point-max))
  403. (user-error
  404. (format "Select a region for colorizing and press \"%s\""
  405. (or (make-color-command-key
  406. 'make-color-set-probing-region)
  407. "M-x make-color-set-probing-region"))))))
  408. (make-color-set-region-as-current (make-color-save-region beg end))
  409. (make-color-update-current-color-maybe))
  410. (defun make-color-command-key (command &optional map)
  411. "Return key bound to COMMAND in MAP.
  412. If MAP is nil, use `make-color-mode-map'.
  413. Return nil, if COMMAND is not bound."
  414. (let ((key (where-is-internal
  415. command (list (or map make-color-mode-map)) t)))
  416. (and key (key-description key))))
  417. (defun make-color-goto-region (&optional arg)
  418. "Switch to the probing region number ARG and highlight it.
  419. Regions are enumerated from 0.
  420. If ARG is nil, highlight current probing region.
  421. Negative ARG means count from the end of saved regions."
  422. (interactive
  423. (list (cond
  424. ((eq '- current-prefix-arg) -1)
  425. ((consp current-prefix-arg) (car current-prefix-arg))
  426. (t current-prefix-arg))))
  427. (if arg
  428. (let ((index (make-color-calc-index arg)))
  429. (if (make-color-get-region index)
  430. (progn
  431. (make-color-set-region-as-current index)
  432. (make-color-update-current-color-maybe)
  433. (make-color-highlight-current-region))
  434. (make-color-set-probing-region)))
  435. (make-color-highlight-current-region)))
  436. (defun make-color-next-region (&optional arg)
  437. "Switch to the next probing region.
  438. With ARG, skip so many regions."
  439. (interactive "p")
  440. (or arg (setq arg 1))
  441. (make-color-goto-region (make-color-calc-index nil arg)))
  442. (defun make-color-previous-region (&optional arg)
  443. "Switch to the previous probing region.
  444. With ARG, skip so many regions."
  445. (interactive "p")
  446. (or arg (setq arg 1))
  447. (make-color-next-region (- arg)))
  448. ;;; Highlighting regions
  449. (defface make-color-highlight
  450. '((t :inherit region))
  451. "Face for highlighted region."
  452. :group 'make-color)
  453. (defcustom make-color-highlight-time 0.7
  454. "Time (in seconds) for keeping a region highlighted."
  455. :type 'number
  456. :group 'make-color)
  457. (defvar make-color-highlight-wait-function 'sit-for
  458. "Function used for waiting until highlighting will be removed.
  459. Can be either `sit-for' or `run-at-time'.")
  460. (defvar make-color-highlight-overlay nil
  461. "Overlay used for highlighting a region.")
  462. (defun make-color-delete-highlight-overlay ()
  463. "Delete overlay for highlighting a region."
  464. (delete-overlay make-color-highlight-overlay))
  465. (defun make-color-highlight-region (beg end)
  466. "Highlight the text between BEG and END temporarily.
  467. Use `make-color-highlight-time' variable and
  468. `make-color-highlight' face."
  469. ;; do nothing if highlighting is in progress
  470. (when (or (null (overlayp make-color-highlight-overlay))
  471. (null (overlay-buffer make-color-highlight-overlay)))
  472. (setq make-color-highlight-overlay (make-overlay beg end))
  473. (overlay-put make-color-highlight-overlay
  474. 'face 'make-color-highlight)
  475. (cl-case make-color-highlight-wait-function
  476. (sit-for
  477. (sit-for make-color-highlight-time)
  478. (make-color-delete-highlight-overlay))
  479. (run-at-time
  480. (run-at-time make-color-highlight-time nil
  481. 'make-color-delete-highlight-overlay))
  482. (t (error "Unknown function for waiting %s"
  483. make-color-highlight-wait-function)))))
  484. (defun make-color-highlight-current-region ()
  485. "Highlight current probing region.
  486. See `make-color-highlight-region' for details."
  487. (interactive)
  488. (let ((bounds (make-color-get-probing-region-bounds)))
  489. (if bounds
  490. (progn
  491. (message "Region %d of 0-%d."
  492. make-color-current-region-index
  493. (- (length make-color-region-ring) 1))
  494. (make-color-highlight-region (car bounds) (cdr bounds)))
  495. (make-color-set-probing-region))))
  496. ;;; UI
  497. (define-derived-mode make-color-mode nil "MakeColor"
  498. "Major mode for making color.
  499. \\{make-color-mode-map}"
  500. (make-local-variable 'make-color-current-color)
  501. (make-local-variable 'make-color-region-ring)
  502. (make-local-variable 'make-color-current-region-index)
  503. (make-local-variable 'make-color-shift-step)
  504. (make-local-variable 'make-color-face-keyword))
  505. (defun make-color-check-mode (&optional buffer)
  506. "Raise error if BUFFER is not in `make-color-mode'.
  507. If BUFFER is nil, use current buffer."
  508. (with-current-buffer (or buffer (current-buffer))
  509. (or (eq major-mode 'make-color-mode)
  510. (error "Current buffer should be in make-color-mode"))))
  511. (defun make-color-keyword (symbol)
  512. "Return a keyword same as SYMBOL but with leading `:'.
  513. If SYMBOL is a keyword, return it."
  514. (if (keywordp symbol)
  515. symbol
  516. (make-symbol (concat ":" (symbol-name symbol)))))
  517. (defun make-color-unkeyword (kw)
  518. "Return a symbol same as keyword KW but without leading `:'."
  519. (or (keywordp kw)
  520. (error "Symbol `%s' is not a keyword" kw))
  521. (make-symbol (substring (symbol-name kw) 1)))
  522. (defun make-color-update-sample (color &optional buffer)
  523. "Update current color and text sample in the BUFFER with COLOR.
  524. COLOR should be a list in a form (R G B).
  525. If BUFFER is nil, use current buffer."
  526. (make-color-check-mode buffer)
  527. (with-current-buffer (or buffer (current-buffer))
  528. (let ((bounds (make-color-get-probing-region-bounds)))
  529. (if bounds
  530. (progn
  531. (setq make-color-current-color color
  532. color (apply 'color-rgb-to-hex color))
  533. (funcall make-color-set-color-function
  534. make-color-face-keyword color
  535. (car bounds) (cdr bounds))
  536. (and make-color-show-color
  537. (message "Current color: %s" color)))
  538. (make-color-set-probing-region)))))
  539. ;;;###autoload
  540. (defun make-color (&optional arg)
  541. "Begin to make a color by modifying a text sample.
  542. If region is active, use it as the sample.
  543. The name of the buffer is defined by `make-color-buffer-name'.
  544. If `make-color-use-single-buffer' is non-nil, use an existing
  545. make-color buffer (with ARG, create a new buffer), otherwise
  546. create a new buffer (with ARG, use an existing one)."
  547. (interactive "P")
  548. ;; `sample' is the whole text yanking in make-color buffer;
  549. ;; `region' is a part of this text used for colorizing
  550. (let (sample region)
  551. (if (region-active-p)
  552. (progn
  553. (setq sample (buffer-substring (region-beginning)
  554. (region-end)))
  555. (when make-color-use-whole-sample
  556. (setq region (cons nil nil))))
  557. (setq sample make-color-sample
  558. region (cons make-color-sample-beg
  559. make-color-sample-end)))
  560. (pop-to-buffer-same-window
  561. (make-color-get-buffer
  562. 'clear
  563. (if make-color-use-single-buffer arg (null arg))))
  564. (make-color-mode)
  565. (insert sample)
  566. (goto-char (point-min))
  567. (and region
  568. (make-color-set-probing-region
  569. (car region) (cdr region) t))))
  570. (defun make-color-set-step (step)
  571. "Set `make-color-shift-step' to a value STEP.
  572. Interactively, prompt for STEP."
  573. (interactive
  574. (list (read-number "Set step to: " make-color-shift-step)))
  575. (if (and (floatp step)
  576. (>= 1.0 step)
  577. (<= 0.0 step))
  578. (setq make-color-shift-step step)
  579. (error "Should be a value from 0.0 to 1.0")))
  580. (defun make-color-set-current-color ()
  581. "Set current color to the prompted value and update probing region."
  582. (interactive)
  583. (let ((color (read-color
  584. (concat "Color"
  585. (and make-color-current-color
  586. (format " (current: %s)"
  587. (apply 'color-rgb-to-hex
  588. make-color-current-color)))
  589. ": "))))
  590. (unless (string= color "")
  591. (make-color-update-sample (color-name-to-rgb color)))))
  592. (defun make-color-update-current-color-maybe ()
  593. "Update current color if needed.
  594. See `make-color-new-color-after-region-change'."
  595. (when make-color-new-color-after-region-change
  596. (let ((bounds (make-color-get-probing-region-bounds)))
  597. (and bounds
  598. (setq make-color-current-color
  599. (color-name-to-rgb
  600. (save-excursion
  601. (goto-char (car bounds))
  602. (make-color-get-color-at-pos
  603. make-color-face-keyword))))))))
  604. (defun make-color-use-foreground ()
  605. "Set foreground as the parameter for further changing."
  606. (interactive)
  607. (setq-local make-color-face-keyword :foreground)
  608. (make-color-update-current-color-maybe)
  609. (message "Foreground has been set for colorizing."))
  610. (defun make-color-use-background ()
  611. "Set background as the parameter for further changing."
  612. (interactive)
  613. (setq-local make-color-face-keyword :background)
  614. (make-color-update-current-color-maybe)
  615. (message "Background has been set for colorizing."))
  616. (defun make-color-toggle-face-parameter ()
  617. "Switch between setting foreground and background."
  618. (interactive)
  619. (if (equal make-color-face-keyword :foreground)
  620. (make-color-use-background)
  621. (make-color-use-foreground)))
  622. (defun make-color-to-kill-ring (color)
  623. "Add color value of COLOR to the `kill-ring'.
  624. COLOR can be a string (color name or a hex value) or a list in a
  625. form (R G B)."
  626. (when (listp color)
  627. (setq color (apply 'color-rgb-to-hex color)))
  628. (kill-new color)
  629. (message "Color '%s' has been put into kill-ring." color))
  630. (defun make-color-current-color-to-kill-ring ()
  631. "Add current color to the `kill-ring'."
  632. (interactive)
  633. (or make-color-current-color
  634. (error "make-color-current-color is nil"))
  635. (make-color-to-kill-ring make-color-current-color))
  636. ;;;###autoload
  637. (defun make-color-foreground-color-to-kill-ring ()
  638. "Add foreground color at point to the `kill-ring'."
  639. (interactive)
  640. (make-color-to-kill-ring (make-color-foreground-color-at-point)))
  641. ;;;###autoload
  642. (defun make-color-background-color-to-kill-ring ()
  643. "Add background color at point to the `kill-ring'."
  644. (interactive)
  645. (make-color-to-kill-ring (make-color-background-color-at-point)))
  646. (provide 'make-color)
  647. ;;; make-color.el ends here