PageRenderTime 79ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/predictive/auto-overlay-self.el

https://github.com/specialstephen/emacsdots
Emacs Lisp | 366 lines | 135 code | 71 blank | 160 comment | 0 complexity | 1b2eafd9204da3947a48a11a65ebad77 MD5 | raw file
  1. ;;; auto-overlay-self.el --- self-delimited automatic overlays
  2. ;; Copyright (C) 2005-2007 Toby Cubitt
  3. ;; Author: Toby Cubitt <toby-predictive@dr-qubit.org>
  4. ;; Version: 0.2.8
  5. ;; Keywords: automatic, overlays, self
  6. ;; URL: http://www.dr-qubit.org/emacs.php
  7. ;; This file is part of the Emacs Automatic Overlays package.
  8. ;;
  9. ;; This program is free software; you can redistribute it and/or
  10. ;; modify it under the terms of the GNU General Public License
  11. ;; as published by the Free Software Foundation; either version 2
  12. ;; of the License, or (at your option) any later version.
  13. ;;
  14. ;; This program is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;; GNU General Public License for more details.
  18. ;;
  19. ;; You should have received a copy of the GNU General Public License
  20. ;; along with this program; if not, write to the Free Software
  21. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  22. ;; MA 02110-1301, USA.
  23. ;;; Change Log:
  24. ;;
  25. ;; Version 0.2.8
  26. ;; * renamed 'entry-id and 'subentry-id to 'definition-id and 'regexp-id
  27. ;;
  28. ;; Version 0.2.7
  29. ;; * fixed bug in `auto-o-parse-self-match' which caused a matched self match
  30. ;; to have null 'parent property if a new self match was created inside an
  31. ;; existing self overlay
  32. ;;
  33. ;; Version 0.2.6
  34. ;; * set overlay properties straight after creation in `auto-o-make-self',
  35. ;; rather than leaving it to `auto-overlay-update', in case matching causes
  36. ;; exclusive reparsing, for which properties are already required
  37. ;;
  38. ;; Version 0.2.5
  39. ;; * removed `auto-overlay-functions' and changed to use new interface
  40. ;;
  41. ;; Version 0.2.4
  42. ;; * fixed(?) bug in auto-o-self-list that caused it to
  43. ;; sometimes miss out the parent overlay itself from the list
  44. ;;
  45. ;; Version 0.2.3
  46. ;; * updated to reflect changes in `auto-overlays.el'
  47. ;; * changed `auto-o-self-list' to make it run faster
  48. ;;
  49. ;; Version 0.2.2
  50. ;; * small but important bug fix
  51. ;;
  52. ;; Version 0.2.1
  53. ;; * bug fixes
  54. ;;
  55. ;; Version 0.2
  56. ;; * substantially re-written to postpone cascading until absolutely
  57. ;; necessary, for improved responsiveness
  58. ;;
  59. ;; Version 0.1
  60. ;; * initial version separated off from auto-overlays.el
  61. ;;; Code:
  62. (require 'auto-overlays)
  63. (provide 'auto-overlay-self)
  64. (defvar auto-o-pending-self-cascade nil)
  65. ;; set self overlay parsing and suicide functions
  66. (put 'self 'auto-overlay-parse-function 'auto-o-parse-self-match)
  67. (put 'self 'auto-overlay-suicide-function 'auto-o-self-suicide)
  68. ;; add initialisation and clear functions to hooks
  69. (add-hook 'auto-overlay-load-hook 'auto-o-self-load)
  70. (add-hook 'auto-overlay-unload-hook 'auto-o-self-unload)
  71. (defun auto-o-self-load ()
  72. ;; Make sure `auto-o-perform-self-cascades' is in `before-change-functions',
  73. ;; so that any cascading that is required is performed before anything else
  74. ;; happens.
  75. (add-hook 'before-change-functions 'auto-o-perform-self-cascades
  76. nil t)
  77. ;; initialise variables
  78. (setq auto-o-pending-self-cascade nil)
  79. )
  80. (defun auto-o-self-unload ()
  81. ;; Remove `auto-o-perform-self-cascades' from `before-change-functions'.
  82. (remove-hook 'before-change-functions 'auto-o-perform-self-cascades t)
  83. )
  84. (defun auto-o-parse-self-match (o-match)
  85. ;; perform any necessary updates of auto overlays due to a match for a self
  86. ;; regexp
  87. (let* ((overlay-list (auto-o-self-list o-match))
  88. (o (car overlay-list)))
  89. (cond
  90. ;; if stack is empty, create a new end-unmatched overlay, adding it to
  91. ;; the list of unascaded overlays (avoids treating it as a special
  92. ;; case), and return it
  93. ((null overlay-list)
  94. (auto-o-make-self o-match nil))
  95. ;; if new delimiter is inside the first existing overlay and existing one
  96. ;; is end-unmatched, just match it
  97. ((and (not (overlay-get o 'end))
  98. (>= (overlay-get o-match 'delim-start) (overlay-start o)))
  99. (auto-o-match-overlay o nil o-match 'no-props)
  100. ;; remove it from the list of uncascaded overlays
  101. (setq auto-o-pending-self-cascade (delq o auto-o-pending-self-cascade))
  102. ;; return nil since haven't created any new overlays
  103. nil)
  104. ;; otherwise...
  105. (t
  106. (let (o-new)
  107. ;; if the new match is outside existing overlays...
  108. (if (< (overlay-get o-match 'delim-end) (overlay-start o))
  109. ;; create overlay from new match till start of next match, and add
  110. ;; it to the list of uncascaded overlays
  111. (setq o-new (auto-o-make-self
  112. o-match
  113. (overlay-get (overlay-get o 'start) 'delim-start)))
  114. ;; if the new match is inside an existing overlay...
  115. (setq o (pop overlay-list))
  116. ;; create overlay from end of existing one till start of the one
  117. ;; after (or end of buffer if there isn't one), and add it to the
  118. ;; list of uncascaded overlays
  119. (setq o-new (auto-o-make-self
  120. (overlay-get o 'end)
  121. (when overlay-list
  122. (overlay-get (overlay-get (car overlay-list) 'start)
  123. 'delim-start))))
  124. ;; match end of existing one with the new match, protecting its old
  125. ;; end match which is now matched with start of new one
  126. (auto-o-match-overlay o nil o-match 'no-props nil 'protect-match))
  127. ;; return newly created overlay
  128. o-new))
  129. ))
  130. )
  131. (defun auto-o-self-suicide (o-self)
  132. ;; Called when match no longer matches. Unmatch the match overlay O-SELF, if
  133. ;; necessary deleting its parent overlay or cascading.
  134. (let ((o-parent (overlay-get o-self 'parent)))
  135. (cond
  136. ;; if parent is end-unmatched, delete it from buffer and from list of
  137. ;; uncascaded overlays
  138. ((not (auto-o-end-matched-p o-parent))
  139. (auto-o-delete-overlay o-parent)
  140. (setq auto-o-pending-self-cascade
  141. (delq o-parent auto-o-pending-self-cascade)))
  142. ;; if we match the end of parent...
  143. ((eq (overlay-get o-parent 'end) o-self)
  144. ;; unmatch ourselves from parent and extend parent till next overlay, or
  145. ;; end of buffer if there is none
  146. (let ((o (nth 1 (auto-o-self-list o-self))))
  147. (auto-o-match-overlay
  148. o-parent nil (if o (overlay-get (overlay-get o 'start) 'delim-start)
  149. 'unmatched)))
  150. ;; add parent to uncascaded overlay list
  151. (push o-parent auto-o-pending-self-cascade))
  152. ;; if we match the start of parent...
  153. (t
  154. (let* ((o-end (overlay-get o-parent 'end))
  155. (o (nth 1 (auto-o-self-list o-end))))
  156. ;; unmatch ourselves from parent and "flip"
  157. (auto-o-match-overlay
  158. o-parent o-end
  159. (if o (overlay-get (overlay-get o 'start) 'delim-start)
  160. 'unmatched)))
  161. ;; add parent to uncascaded overlay list
  162. (push o-parent auto-o-pending-self-cascade))
  163. ))
  164. )
  165. (defun auto-o-make-self (o-start &optional end)
  166. ;; Create a self overlay starting at match overlay O-START.
  167. ;; If END is a number or marker, the new overlay is end-unmatched and ends
  168. ;; at the buffer location specified by the number or marker.
  169. ;; If END is nil, the new overlay is end-unmatched and ends at the end of
  170. ;; the buffer.
  171. (let (o-new)
  172. ;; create new overlay (location ensures right things happen when matched)
  173. (let (pos)
  174. (cond
  175. ((overlayp end) (setq pos (overlay-get end 'delim-start)))
  176. ((number-or-marker-p end) (setq pos end))
  177. (t (setq pos (point-max))))
  178. (setq o-new (make-overlay pos pos nil nil 'rear-advance)))
  179. ;; give overlay some basic properties
  180. (overlay-put o-new 'auto-overlay t)
  181. (overlay-put o-new 'set-id (overlay-get o-start 'set-id))
  182. (overlay-put o-new 'definition-id (overlay-get o-start 'definition-id))
  183. ;; if overlay is end-unmatched, add it to the list of uncascaded overlays
  184. (unless (overlayp end) (push o-new auto-o-pending-self-cascade))
  185. ;; match the new overlay and return it
  186. (auto-o-match-overlay o-new o-start (if (overlayp end) end nil))
  187. o-new)
  188. )
  189. (defun auto-o-perform-self-cascades (beg end)
  190. ;; Perform any necessary self-overlay cascading before the text in the
  191. ;; buffer is modified. Called from `before-change-functions'.
  192. ;; check all overlays waiting to be cascaded, from first in buffer to last
  193. (dolist (o (sort auto-o-pending-self-cascade
  194. (lambda (a b) (< (overlay-start a) (overlay-start b)))))
  195. ;; if buffer modification occurs after the end of an overlay waiting to be
  196. ;; cascaded, cascade all overlays between it and the modified text
  197. (when (and (overlay-end o) (< (overlay-end o) end))
  198. (auto-o-self-cascade (auto-o-self-list (overlay-get o 'start) end))))
  199. )
  200. (defun auto-o-self-cascade (overlay-list)
  201. ;; "Flip" overlays down through buffer (assumes first overlay in list is
  202. ;; end-unmatched).
  203. (when (> (length overlay-list) 1)
  204. (let ((o (car overlay-list))
  205. (o1 (nth 1 overlay-list)))
  206. ;; match first (presumably end-matched) overlay and remove it from list
  207. (pop overlay-list)
  208. (auto-o-match-overlay o nil (overlay-get o1 'start) 'no-props)
  209. ;; remove it from list of uncascaded overlays
  210. (setq auto-o-pending-self-cascade (delq o auto-o-pending-self-cascade))
  211. ;; if we've hit an end-unmatched overlay, we can stop cascading
  212. (if (not (auto-o-end-matched-p o1))
  213. (progn
  214. (auto-o-delete-overlay o1 nil 'protect-match)
  215. (setq auto-o-pending-self-cascade
  216. (delq o1 auto-o-pending-self-cascade)))
  217. ;; otherwise, cascade overlay list till one is left or we hit an
  218. ;; end-unmached overlay
  219. (unless
  220. (catch 'stop
  221. (dotimes (i (1- (length overlay-list)))
  222. (setq o (nth i overlay-list))
  223. (setq o1 (nth (1+ i) overlay-list))
  224. (auto-o-match-overlay o (overlay-get o 'end)
  225. (overlay-get o1 'start)
  226. 'no-props nil 'protect-match)
  227. ;; if we hit an end-unmatched overlay, we can stop cascading
  228. (when (not (auto-o-end-matched-p o1))
  229. (throw 'stop (progn
  230. ;; delete the end-unmatched overlay
  231. (auto-o-delete-overlay o1 nil 'protect-match)
  232. ;; remove it from uncascaded overlays list
  233. (setq auto-o-pending-self-cascade
  234. (delq o1 auto-o-pending-self-cascade))
  235. ;; return t to indicate cascading ended early
  236. t)))))
  237. ;; if there's an overlay left, "flip" it so it's end-unmatched and
  238. ;; extends to next overlay in buffer, and add it to the list of
  239. ;; unmatched overlays
  240. (let (pos)
  241. (setq o (car (last overlay-list)))
  242. (if (setq o1 (nth 1 (auto-o-self-list (overlay-get o 'end))))
  243. (setq pos (overlay-get (overlay-get o1 'start) 'delim-start))
  244. (setq pos (point-max)))
  245. (auto-o-match-overlay o (overlay-get o 'end) pos
  246. 'no-props nil 'protect-match))
  247. (push o auto-o-pending-self-cascade)))
  248. ))
  249. )
  250. ;; (defun auto-o-self-list (o-start &optional end)
  251. ;; ;; Return list of self overlays ending at or after match overlay O-START and
  252. ;; ;; starting before or at END, corresponding to same entry as O-START. If END
  253. ;; ;; is null, all overlays after O-START are included.
  254. ;; (when (null end) (setq end (point-max)))
  255. ;; (let (overlay-list)
  256. ;; ;; create list of all overlays corresponding to same entry between O-START
  257. ;; ;; and END
  258. ;; (mapc (lambda (o) (when (and (>= (overlay-end o)
  259. ;; (overlay-get o-start 'delim-start))
  260. ;; (<= (overlay-start o) end))
  261. ;; (push o overlay-list)))
  262. ;; (auto-overlays-in
  263. ;; (point-min) (point-max)
  264. ;; (list
  265. ;; '(identity auto-overlay)
  266. ;; (list 'eq 'set-id (overlay-get o-start 'set-id))
  267. ;; (list 'eq 'definition-id (overlay-get o-start 'definition-id)))))
  268. ;; ;; sort the list by start position, from first to last
  269. ;; (sort overlay-list
  270. ;; (lambda (a b) (< (overlay-start a) (overlay-start b)))))
  271. ;; )
  272. (defun auto-o-self-list (o-start &optional end)
  273. ;; Return list of self overlays ending at or after match overlay O-START and
  274. ;; starting before or at END, corresponding to same entry as O-START. If END
  275. ;; is null, all overlays after O-START are included.
  276. (when (null end) (setq end (point-max)))
  277. (let (overlay-list)
  278. ;; create list of all overlays corresponding to same entry between O-START
  279. ;; and END
  280. (setq overlay-list
  281. ;; Note: We subtract 1 from start and add 1 to end to catch overlays
  282. ;; that end at start or start at end. This seems to give the
  283. ;; same results as the old version of `auto-o-self-list'
  284. ;; (above) in all circumstances.
  285. (auto-overlays-in
  286. (1- (overlay-get o-start 'delim-start)) (1+ end)
  287. (list
  288. '(identity auto-overlay)
  289. (list 'eq 'set-id (overlay-get o-start 'set-id))
  290. (list 'eq 'definition-id (overlay-get o-start 'definition-id)))))
  291. ;; sort the list by start position, from first to last
  292. (sort overlay-list
  293. (lambda (a b) (< (overlay-start a) (overlay-start b)))))
  294. )
  295. ;;; auto-overlay-self.el ends here