Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

686 lines
26 KiB

  1. ;;; ov.el --- Overlay library for Emacs Lisp -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2014 by Shingo Fukuyama
  3. ;; Version: 1.0.6
  4. ;; Package-Version: 20200326.1042
  5. ;; Package-Commit: c5b9aa4e1b00d702eb2caedd61c69a22a5fa1fab
  6. ;; Author: Shingo Fukuyama - http://fukuyama.co
  7. ;; URL: https://github.com/ShingoFukuyama/ov.el
  8. ;; Created: Mar 20 2014
  9. ;; Keywords: convenience overlay
  10. ;; Package-Requires: ((emacs "24.3"))
  11. ;; This program is free software; you can redistribute it and/or
  12. ;; modify it under the terms of the GNU General Public License as
  13. ;; published by the Free Software Foundation; either version 2 of
  14. ;; the License, or (at your option) any later version.
  15. ;; This program is distributed in the hope that it will be
  16. ;; useful, but WITHOUT ANY WARRANTY; without even the implied
  17. ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  18. ;; PURPOSE. See the GNU General Public License for more details.
  19. ;;; Commentary:
  20. ;; Simple way to manipulate overlay for Emacs.
  21. ;; More information is in README.md or https://github.com/ShingoFukuyama/ov.el
  22. ;;; Code:
  23. (require 'cl-lib)
  24. (defgroup ov nil
  25. "Group for ov.el"
  26. :prefix "ov-" :group 'development)
  27. (defvar ov-sticky-front nil)
  28. (defvar ov-sticky-rear nil)
  29. ;; http://www.gnu.org/software/emacs/manual/html_node/elisp/Overlay-Properties.html
  30. (defvar ov-prop-list '(priority
  31. window
  32. category
  33. face
  34. mouse-face
  35. display
  36. help-echo
  37. field
  38. modification-hooks
  39. insert-in-front-hooks
  40. insert-behind-hooks
  41. invisible
  42. intangible
  43. isearch-open-invisible
  44. isearch-open-invisible-temporary
  45. before-string
  46. after-string
  47. line-prefix
  48. wrap-prefix
  49. evaporate
  50. local-map
  51. keymap))
  52. ;; Make overlay / Set properties -----------------------------------------------
  53. ;; Just make an overlay from `beg' and `end'.
  54. ;; Alias ;; Argument
  55. (defalias 'ov-create 'make-overlay) ;; (beg end)
  56. (defalias 'ov-make 'make-overlay) ;; (beg end)
  57. (defun ov (beg end &rest properties)
  58. "Make an overlay from BEG to END.
  59. If PROPERTIES are specified, set them for the created overlay."
  60. (if properties
  61. (progn
  62. ;; To pass properties to `ov-set'
  63. (when (listp (car-safe properties))
  64. (setq properties (car properties)))
  65. (let ((o (ov-make beg end nil (not ov-sticky-front) ov-sticky-rear)))
  66. (ov-set o properties)
  67. o))
  68. (ov-make beg end nil (not ov-sticky-front) ov-sticky-rear)))
  69. (defun ov-line (&optional point)
  70. "Make an overlay from the beginning of the line to the beginning of the next line, which include POINT."
  71. (let (o)
  72. (save-excursion
  73. (goto-char (or point (point)))
  74. (setq o (ov-make (point-at-bol) (min (1+ (point-at-eol)) (point-max))
  75. nil (not ov-sticky-front) ov-sticky-rear)))
  76. o))
  77. (defun ov-match (string &optional beg end)
  78. "Make overlays spanning the regions that match STRING.
  79. If BEG and END are numbers, they specify the bounds of the search."
  80. (save-excursion
  81. (goto-char (or beg (point-min)))
  82. (let (ov-or-ovs)
  83. (ov-recenter (point-max))
  84. (while (search-forward string end t)
  85. (setq ov-or-ovs (cons (ov-make (match-beginning 0)
  86. (match-end 0)
  87. nil (not ov-sticky-front) ov-sticky-rear)
  88. ov-or-ovs)))
  89. ov-or-ovs)))
  90. (defun ov-regexp (regexp &optional beg end)
  91. "Make overlays spanning the regions that match REGEXP.
  92. If BEG and END are numbers, they specify the bounds of the search."
  93. (save-excursion
  94. (goto-char (or beg (point-min)))
  95. (let (ov-or-ovs finish)
  96. (ov-recenter (point-max))
  97. (while (and (not finish) (re-search-forward regexp end t))
  98. (setq ov-or-ovs (cons (ov-make (match-beginning 0)
  99. (match-end 0)
  100. nil (not ov-sticky-front) ov-sticky-rear)
  101. ov-or-ovs))
  102. (when (= (match-beginning 0) (match-end 0))
  103. (if (eobp)
  104. (setq finish t)
  105. (forward-char 1))))
  106. ov-or-ovs)))
  107. (defun ov-region ()
  108. "Make an overlay from a region if region is active."
  109. (if (use-region-p)
  110. (let ((o (ov-make (region-beginning) (region-end)
  111. nil (not ov-sticky-front) ov-sticky-rear)))
  112. (deactivate-mark t)
  113. o)
  114. (error "Need to make region")))
  115. (defun ov-set (ov-or-ovs-or-regexp &rest properties)
  116. "Set overlay properties and values.
  117. OV-OR-OVS-OR-REGEXP can be an overlay, overlays or a regexp.
  118. If an overlay or list of overlays, PROPERTIES are set for these.
  119. If a regexp, first overlays are created on the matching
  120. regions (see `ov-regexp'), then the properties are set."
  121. (when ov-or-ovs-or-regexp
  122. (unless (and ov-or-ovs-or-regexp properties)
  123. (error "Arguments are OV and PROPERTIES"))
  124. (when (listp (car-safe properties))
  125. (setq properties (car properties)))
  126. (let ((len (length properties))
  127. (i 0)
  128. return-type)
  129. (cond ((stringp ov-or-ovs-or-regexp)
  130. (setq ov-or-ovs-or-regexp (ov-regexp ov-or-ovs-or-regexp))
  131. (setq return-type 'ov-list))
  132. ((ov-p ov-or-ovs-or-regexp)
  133. (setq ov-or-ovs-or-regexp (cons ov-or-ovs-or-regexp nil))
  134. (setq return-type 'ov))
  135. ((listp ov-or-ovs-or-regexp)
  136. (setq return-type 'ov-list)))
  137. (unless (eq (logand len 1) 0)
  138. (error "Invalid properties pairs"))
  139. (mapc (lambda (ov)
  140. (while (< i len)
  141. (overlay-put
  142. ov
  143. (nth i properties) (nth (setq i (1+ i)) properties))
  144. (setq i (1+ i)))
  145. (setq i 0))
  146. ov-or-ovs-or-regexp)
  147. (if (eq 'ov return-type)
  148. (car ov-or-ovs-or-regexp)
  149. ov-or-ovs-or-regexp))))
  150. (defalias 'ov-put 'ov-set)
  151. (defun ov-insert (any)
  152. "Insert ANY (string, number, list, etc) covered with an empty overlay."
  153. (or (stringp any) (setq any (format "%s" any)))
  154. (let* ((beg (point))
  155. (len (length any))
  156. (end (+ beg len)))
  157. (insert any)
  158. (ov-make beg end nil (not ov-sticky-front) ov-sticky-rear)))
  159. ;; Delete overlay --------------------------------------------------------------
  160. ;;;###autoload
  161. (cl-defun ov-clear (&optional prop-or-beg (val-or-end 'any) beg end)
  162. "Clear overlays satisfying a condition.
  163. If PROP-OR-BEG is a symbol, clear overlays with this property set to non-nil.
  164. If VAL-OR-END is non-nil, the specified property's value should
  165. `equal' to this value.
  166. If both of these are numbers, clear the overlays between these points.
  167. If BEG and END are numbers, clear the overlays with specified
  168. property and value between these points.
  169. With no arguments, clear all overlays in the buffer."
  170. (interactive)
  171. (cl-labels ((clear
  172. (con beg end)
  173. (ov-recenter (or end (point-max)))
  174. (mapc (lambda (ov)
  175. (when (and (memq prop-or-beg (ov-prop ov))
  176. (if con
  177. t (equal val-or-end (ov-val ov prop-or-beg))))
  178. (delete-overlay ov)))
  179. (overlays-in beg end))))
  180. (cond
  181. ;; (ov-clear)
  182. ((and (not prop-or-beg) (eq 'any val-or-end) (not beg) (not end))
  183. (ov-recenter (point-max))
  184. (remove-overlays (point-min) (point-max)))
  185. ;; (ov-clear 10 500)
  186. ((and (numberp prop-or-beg) (numberp val-or-end))
  187. (ov-recenter val-or-end)
  188. (remove-overlays prop-or-beg val-or-end))
  189. ;; (ov-clear 'face 'warning)
  190. ((and (symbolp prop-or-beg) (not (eq 'any val-or-end)) (not beg) (not end))
  191. (clear nil (point-min) (point-max)))
  192. ;; (ov-clear 'face) or (ov-clear 'face 'any)
  193. ((and (symbolp prop-or-beg) (eq 'any val-or-end) (not beg) (not end))
  194. (clear t (point-min) (point-max)))
  195. ;; (ov-clear 'face 'worning 10 500)
  196. ((and (symbolp prop-or-beg) (not (eq 'any val-or-end)) (numberp beg) (numberp end))
  197. (clear nil beg end))
  198. ;; (ov-clear 'face 'any 10 500)
  199. ((and (symbolp prop-or-beg) (eq 'any val-or-end) (numberp beg) (numberp end))
  200. (clear t beg end))
  201. (t nil)))
  202. nil)
  203. (defmacro ov-reset (ov-or-ovs-variable)
  204. "Clear overlays in OV-OR-OVS-VARIABLE.
  205. OV-OR-OVS-VARIABLE should be a symbol whose value is an overlay
  206. or a list of overlays.
  207. Finally, the variable is set to nil."
  208. `(progn
  209. (mapc (lambda (ov)
  210. (delete-overlay ov))
  211. (if (listp ,ov-or-ovs-variable)
  212. ,ov-or-ovs-variable
  213. (cons ,ov-or-ovs-variable nil)))
  214. (setq ,ov-or-ovs-variable nil)))
  215. ;; Look up overlay parameters, etc ---------------------------------------------
  216. ;; Alias ;; Argument
  217. ;; Check whether `ov' is overlay or not.
  218. (defalias 'ov-p 'overlayp) ;; (ov)
  219. (defalias 'ov? 'overlayp) ;; (ov)
  220. (defalias 'ov-val 'overlay-get) ;; (ov property)
  221. ;; Get the boundary position of an overlay.
  222. (defalias 'ov-beg 'overlay-start) ;; (ov)
  223. (defalias 'ov-end 'overlay-end) ;; (ov)
  224. ;; Get the buffer object of an overlay.
  225. (defalias 'ov-buf 'overlay-buffer) ;; (ov)
  226. ;; Get the properties from an overlay.
  227. (defalias 'ov-prop 'overlay-properties) ;; (ov)
  228. (defun ov-length (overlay)
  229. "Return the length of the region spanned by OVERLAY."
  230. (- (ov-end overlay) (ov-beg overlay)))
  231. (defun ov-spec (ov-or-ovs)
  232. "Make an overlay specification list.
  233. This is of the form:
  234. (beginning end buffer &rest properties).
  235. OV-OR-OVS should be an overlay or a list of overlays."
  236. (or (listp ov-or-ovs) (setq ov-or-ovs (cons ov-or-ovs nil)))
  237. (mapcar (lambda (ov)
  238. (list (ov-beg ov) (ov-end ov)
  239. (ov-buf ov) (overlay-properties ov)))
  240. ov-or-ovs))
  241. ;; Get present overlay object --------------------------------------------------
  242. (defun ov-at (&optional point)
  243. "Get an overlay at POINT.
  244. POINT defaults to the current `point'."
  245. (or point (setq point (point)))
  246. (car (overlays-at point)))
  247. ;; Get overlays between `beg' and `end'.
  248. (cl-defun ov-in (&optional prop-or-beg (val-or-end 'any) beg end)
  249. "Get overlays satisfying a condition.
  250. If PROP-OR-BEG is a symbol, get overlays with this property set to non-nil.
  251. If VAL-OR-END is non-nil, the specified property's value should
  252. `equal' to this value.
  253. If both of these are numbers, get the overlays between these points.
  254. If BEG and END are numbers, get the overlays with specified
  255. property and value between these points.
  256. With no arguments, get all overlays in the buffer."
  257. (cl-labels ((in (con beg end)
  258. (delq nil
  259. (mapcar
  260. (lambda ($ov)
  261. (when (and (memq prop-or-beg (ov-prop $ov))
  262. (if con
  263. t (equal val-or-end (ov-val $ov prop-or-beg))))
  264. $ov))
  265. (overlays-in beg end)))))
  266. (cond
  267. ;; (ov-in)
  268. ((and (not prop-or-beg) (eq 'any val-or-end) (not beg) (not end))
  269. (overlays-in (point-min) (point-max)))
  270. ;; (ov-in 10 500)
  271. ((and (numberp prop-or-beg) (numberp val-or-end))
  272. (overlays-in prop-or-beg val-or-end))
  273. ;; (ov-in 'face 'warning)
  274. ((and (symbolp prop-or-beg) (not (eq 'any val-or-end)) (not beg) (not end))
  275. (in nil (point-min) (point-max)))
  276. ;; (ov-in 'face) or (ov-in 'face 'any)
  277. ((and (symbolp prop-or-beg) (eq 'any val-or-end) (not beg) (not end))
  278. (in t (point-min) (point-max)))
  279. ;; (ov-in 'face 'worning 10 500)
  280. ((and (symbolp prop-or-beg) (not (eq 'any val-or-end)) (numberp beg) (numberp end))
  281. (in nil beg end))
  282. ;; (ov-in 'face 'any 10 500)
  283. ((and (symbolp prop-or-beg) (eq 'any val-or-end) (numberp beg) (numberp end))
  284. (in t beg end))
  285. (t nil))))
  286. (defun ov-all ()
  287. "Get all the overlays in the entire buffer."
  288. (overlays-in (point-min) (point-max)))
  289. (defun ov-backwards (&optional point)
  290. "Get all the overlays from the beginning of the buffer to POINT."
  291. (ov-in (point-min) (or point (point))))
  292. (defun ov-forwards (&optional point)
  293. "Get all the overlays from POINT to the end of the buffer."
  294. (ov-in (or point (point)) (point-max)))
  295. ;; Overlay manipulation --------------------------------------------------------
  296. ;; Alias ;; Argument
  297. (defalias 'ov-recenter 'overlay-recenter) ;; (point)
  298. ;; Move an existing overlay position to another position.
  299. (defalias 'ov-move 'move-overlay) ;; (ov beg end &optional buffer)
  300. (defmacro ov-timeout (time func func-after)
  301. "Execute FUNC-AFTER after TIME seconds passed since FUNC finished."
  302. (declare (indent 1))
  303. (if (symbolp func-after)
  304. (run-with-timer time nil `(lambda () (funcall ',func-after)))
  305. (run-with-timer time nil `(lambda () ,(funcall `(lambda () ,func-after)))))
  306. (if (symbolp func)
  307. (funcall func)
  308. (funcall (lambda () (eval func)))))
  309. (cl-defun ov-next (&optional point-or-prop prop-or-val (val 'any))
  310. "Get the next overlay satisfying a condition.
  311. If POINT-OR-PROP is a symbol, get the next overlay with this
  312. property being non-nil.
  313. If PROP-OR-VAL is non-nil, the property should have this value.
  314. If POINT-OR-PROP is a number, get the next overlay after this
  315. point.
  316. If PROP-OR-VAL and VAL are also specified, get the next overlay
  317. after POINT-OR-PROP having property PROP-OR-VAL set to VAL (with
  318. VAL unspecified, only the presence of property is tested)."
  319. (cl-labels ((next
  320. (po pr va)
  321. (save-excursion
  322. (goto-char (next-overlay-change po))
  323. (let (ov)
  324. (while (and (not (if (setq ov (ov-at (point)))
  325. (and (memq pr (ov-prop ov))
  326. (if (eq 'any va)
  327. t (equal va (ov-val ov pr))))))
  328. (not (if (eobp) (progn (setq ov nil) t))))
  329. (goto-char (next-overlay-change (point))))
  330. ov))))
  331. (cond
  332. ;; (ov-next) or (ov-next 300)
  333. ((and (or (numberp point-or-prop) (not point-or-prop))
  334. (not prop-or-val) (eq 'any val))
  335. (let* ((po (next-overlay-change (or point-or-prop (point))))
  336. (ov (ov-at po)))
  337. (if (ov? ov)
  338. ov
  339. (ov-at (next-overlay-change po)))))
  340. ;; (ov-next 'face)
  341. ((and point-or-prop (symbolp point-or-prop) (not prop-or-val) (eq 'any val))
  342. (next (point) point-or-prop 'any))
  343. ;; (ov-next 'face 'warning)
  344. ((and point-or-prop (symbolp point-or-prop) prop-or-val (eq 'any val))
  345. (next (point) point-or-prop prop-or-val))
  346. ;; (ov-next 300 'face 'warning)
  347. ((and (or (not point-or-prop) (numberp point-or-prop))
  348. (symbolp prop-or-val) (not (eq 'any val)))
  349. (next (or point-or-prop (point)) prop-or-val val))
  350. ;; (ov-next 300 'face)
  351. ((and (or (numberp point-or-prop) (not point-or-prop)) (symbolp prop-or-val))
  352. (next (or point-or-prop (point)) prop-or-val val))
  353. (t nil))))
  354. (cl-defun ov-prev (&optional point-or-prop prop-or-val (val 'any))
  355. "Get the previous overlay satisfying a condition.
  356. If POINT-OR-PROP is a symbol, get the previous overlay with this
  357. property being non-nil.
  358. If PROP-OR-VAL is non-nil, the property should have this value.
  359. If POINT-OR-PROP is a number, get the previous overlay after this
  360. point.
  361. If PROP-OR-VAL and VAL are also specified, get the previous
  362. overlay after POINT-OR-PROP having property PROP-OR-VAL set to
  363. VAL (with VAL unspecified, only the presence of property is
  364. tested)."
  365. (cl-labels ((prev
  366. (po pr va)
  367. (save-excursion
  368. (goto-char (previous-overlay-change po))
  369. (let (ov)
  370. (while (and (not (if (setq ov (ov-at (1- (point))))
  371. (and (memq pr (ov-prop ov))
  372. (if (eq 'any va)
  373. t (equal va (ov-val ov pr))))))
  374. (not (if (bobp) (progn (setq ov nil) t))))
  375. (goto-char (previous-overlay-change (point))))
  376. ov))))
  377. (cond
  378. ((and (or (numberp point-or-prop) (not point-or-prop))
  379. (not prop-or-val) (eq 'any val))
  380. (let* ((po1 (previous-overlay-change (point)))
  381. (po2 (previous-overlay-change po1))
  382. (ov (or (ov-at po2) (ov-at (1- po2)))))
  383. (if (ov? ov) ov)))
  384. ;; (ov-prev 'face)
  385. ((and point-or-prop (symbolp point-or-prop) (not prop-or-val) (eq 'any val))
  386. (prev (point) point-or-prop 'any))
  387. ;; (ov-prev 'face 'warning)
  388. ((and point-or-prop (symbolp point-or-prop) prop-or-val (eq 'any val))
  389. (prev (point) point-or-prop prop-or-val))
  390. ;; (ov-prev 300 'face 'warning)
  391. ((and (or (not point-or-prop) (numberp point-or-prop))
  392. (symbolp prop-or-val) (not (eq 'any val)))
  393. (prev (or point-or-prop (point)) prop-or-val val))
  394. ;; (ov-prev 300 'face)
  395. ((and (or (numberp point-or-prop) (not point-or-prop)) (symbolp prop-or-val))
  396. (prev (or point-or-prop (point)) prop-or-val val))
  397. (t nil))))
  398. (cl-defun ov-goto-next (&optional point-or-prop prop-or-val (val 'any))
  399. "Move cursor to the end of the next overlay.
  400. The arguments are the same as for `ov-next'."
  401. (interactive)
  402. (let ((o (ov-next point-or-prop prop-or-val val)))
  403. (if o (goto-char (ov-end o)))))
  404. (cl-defun ov-goto-prev (&optional point-or-prop prop-or-val (val 'any))
  405. "Move cursor to the beginning of previous overlay.
  406. The arguments are the same as for `ov-prev'."
  407. (interactive)
  408. (let ((o (ov-prev point-or-prop prop-or-val val)))
  409. (if o (goto-char (ov-beg o)))))
  410. (defun ov-keymap (ov-or-ovs-or-id &rest keybinds)
  411. "Set KEYBINDS to an overlay or a list of overlays.
  412. If OV-OR-OVS-OR-ID is a symbol, the KEYBINDS will be enabled for
  413. the entire buffer and the property represented by the symbol to t.
  414. The overlay is expanded if new inputs are inserted at the
  415. beginning or end of the buffer."
  416. (let ((map (make-sparse-keymap)))
  417. (when (cl-evenp (length keybinds))
  418. (while keybinds
  419. (let* ((key (pop keybinds))
  420. (fn (pop keybinds))
  421. (command (cl-typecase fn
  422. (command fn)
  423. (cons `(lambda () (interactive) ,fn))
  424. (t (error "Invalid function")))))
  425. (cl-typecase key
  426. (vector (define-key map key command))
  427. (string (define-key map (kbd key) command))
  428. (list (mapc (lambda (k)
  429. (define-key map (cl-typecase k
  430. (vector k)
  431. (string (kbd k))) command))
  432. key))
  433. (t (error "Invalid key"))))))
  434. (if (symbolp ov-or-ovs-or-id)
  435. (let ((ov-sticky-front t)
  436. (ov-sticky-rear t))
  437. (ov (point-min) (point-max) 'keymap map ov-or-ovs-or-id t))
  438. (ov-set ov-or-ovs-or-id 'keymap map))))
  439. ;; Implement pseudo read-only overlay function ---------------------------------
  440. (defun ov-read-only (ov-or-ovs &optional insert-in-front insert-behind)
  441. "Implement a read-only like feature for an overlay or a list of overlays.
  442. If INSERT-IN-FRONT is non-nil, inserting in front of each overlay is prevented.
  443. If INSERT-BEHIND is non-nil, inserting behind of each overlay is prevented.
  444. Note that it allows modifications from out of range of a read-only overlay.
  445. OV-OR-OVS can be an overlay or list of overlay."
  446. (cond ((not (and insert-in-front insert-behind))
  447. (ov-set ov-or-ovs
  448. 'modification-hooks '(ov--read-only)))
  449. ((and insert-in-front insert-behind)
  450. (ov-set ov-or-ovs
  451. 'modification-hooks '(ov--read-only)
  452. 'insert-in-front-hooks '(ov--read-only)
  453. 'insert-behind-hooks '(ov--read-only)))
  454. (insert-in-front
  455. (ov-set ov-or-ovs
  456. 'modification-hooks '(ov--read-only)
  457. 'insert-in-front-hooks '(ov--read-only)))
  458. (t ;; Should be insert-behind
  459. (ov-set ov-or-ovs
  460. 'modification-hooks '(ov--read-only)
  461. 'insert-behind-hooks '(ov--read-only)))))
  462. (defun ov--read-only (ov after beg end &optional _length)
  463. (when (and (not (or after
  464. undo-in-progress
  465. (eq this-command 'undo)
  466. (eq this-command 'redo)))
  467. ;; Modification within range of a text
  468. (or (< (ov-beg ov) beg)
  469. (> (ov-end ov) end)))
  470. (error "Text is read-only")))
  471. ;; Special overlay -------------------------------------------------------------
  472. (defun ov-placeholder (ov-or-ovs)
  473. "Set a placeholder feature for an overlay or a list of overlays.
  474. Each overlay deletes its string and overlay, when it is modified.
  475. OV-OR-OVS can be an overlay or list of overlay."
  476. (ov-set ov-or-ovs
  477. 'evaporate t
  478. 'modification-hooks '(ov--placeholder)
  479. 'insert-in-front-hooks '(ov--placeholder)
  480. 'insert-behind-hooks '(ov--placeholder)))
  481. (defun ov--placeholder (ov after beg end &optional length)
  482. (let ((inhibit-modification-hooks t))
  483. (when (not (or undo-in-progress
  484. (eq this-command 'undo)
  485. (eq this-command 'redo)))
  486. (cond ((and (not after) (eq beg end))
  487. (delete-region (ov-beg ov) (ov-end ov)))
  488. ((and after (> length 0))
  489. (if (ov-beg ov)
  490. (delete-region (ov-beg ov) (ov-end ov))))))))
  491. ;; Smear background ------------------------------------------------------------
  492. (defun ov--parse-hex-color (hex)
  493. "Convert a HEX color code to a RGB list.
  494. i.e.
  495. #99ccff => (153 204 255)
  496. #33a => (51 51 170)"
  497. (let (result)
  498. (when (string-match
  499. "^\\s-*\\#\\([0-9a-fA-F]\\)\\([0-9a-fA-F]\\)\\([0-9a-fA-F]\\)\\s-*$"
  500. hex)
  501. (let ((m1 (match-string 1 hex))
  502. (m2 (match-string 2 hex))
  503. (m3 (match-string 3 hex)))
  504. (setq result (list (read (format "#x%s%s" m1 m1))
  505. (read (format "#x%s%s" m2 m2))
  506. (read (format "#x%s%s" m3 m3))))))
  507. (when (string-match
  508. "^\\s-*\\#\\([0-9a-fA-F]\\{2\\}\\)\\([0-9a-fA-F]\\{2\\}\\)\\([0-9a-fA-F]\\{2\\}\\)\\s-*$"
  509. hex)
  510. (setq result (list (read (format "#x%s" (match-string 1 hex)))
  511. (read (format "#x%s" (match-string 2 hex)))
  512. (read (format "#x%s" (match-string 3 hex))))))
  513. result))
  514. (defun ov--random-color (&optional base-color range)
  515. "Generate random color based on BASE-COLOR and RANGE.
  516. Default background color is used when BASE-COLOR is nil."
  517. (or range (setq range 50))
  518. (let ((default-background-color (ignore-errors (face-attribute 'default :background))))
  519. (or base-color
  520. (setq base-color
  521. (cond ((eq 'unspecified default-background-color)
  522. "#fff")
  523. ((string-match "^#[0-9a-fA-F]\\{3,6\\}" default-background-color)
  524. default-background-color)
  525. ((color-name-to-rgb default-background-color) ;; yellow, LightBlue, etc...
  526. default-background-color)
  527. (t "#fff")))))
  528. (if (color-name-to-rgb base-color)
  529. (let ((rgb) (hex "#"))
  530. (mapc (lambda (x)
  531. (setq rgb (cons (round (* x 255)) rgb)))
  532. (color-name-to-rgb base-color))
  533. (setq rgb (nreverse rgb))
  534. (mapc (lambda (x)
  535. (setq hex (concat hex (format "%02x" x))))
  536. rgb)
  537. (setq base-color hex)))
  538. (let* ((rgb (ov--parse-hex-color base-color))
  539. (half-range (/ range 2))
  540. (fn (lambda (n)
  541. (let* ((base (nth n rgb))
  542. (min half-range)
  543. (max (- 255 half-range))
  544. result)
  545. (if (< base min) (setq base min))
  546. (if (> base max) (setq base max))
  547. (setq result (+ (- (cl-random range) half-range) base))
  548. (if (< result 0) (setq result 0))
  549. (if (> result 255) (setq result 255))
  550. result)))
  551. (r (funcall fn 0))
  552. (g (funcall fn 1))
  553. (b (funcall fn 2)))
  554. (format "#%02x%02x%02x" r g b)))
  555. (defun ov-smear (regexp-or-list &optional match-end base-color color-range)
  556. "Set background color overlays to the current buffer.
  557. Each background color is randomly determined based on BASE-COLOR
  558. or the default background color.
  559. If REGEXP-OR-LIST is regexp
  560. Set overlays between matches of a regexp.
  561. If REGEXP-OR-LIST is list
  562. Set overlays between point pairs in a list.
  563. i.e. (ov-smear '((1 . 30) (30 . 90)))"
  564. (interactive "sSplitter: ")
  565. (ov-clear 'ov-smear)
  566. (let (points area length (counter 0) ov-list)
  567. (cl-typecase regexp-or-list
  568. (string (save-excursion
  569. (goto-char (point-min))
  570. (while (re-search-forward regexp-or-list nil t)
  571. (setq points (cons
  572. (if match-end
  573. (match-end 0)
  574. (match-beginning 0))
  575. points))))
  576. (setq points (nreverse points))
  577. (setq length (length points))
  578. (while (< counter (1- length))
  579. (setq area (cons
  580. (cons
  581. (nth counter points)
  582. (nth (1+ counter) points))
  583. area))
  584. (setq counter (1+ counter))))
  585. (list (setq area regexp-or-list)))
  586. (mapc (lambda (a)
  587. (let ((ov (ov (car a) (cdr a))))
  588. (ov-set ov
  589. 'face `(:background ,(ov--random-color base-color color-range))
  590. 'ov-smear t)
  591. (setq ov-list (cons ov ov-list))))
  592. area)
  593. ov-list))
  594. (provide 'ov)
  595. ;;; ov.el ends here