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.

562 lines
27 KiB

  1. ;;; poly-lock.el --- Font lock sub-system for polymode -*- lexical-binding: t -*-
  2. ;;
  3. ;; Copyright (C) 2013-2019, Vitalie Spinu
  4. ;; Author: Vitalie Spinu
  5. ;; URL: https://github.com/polymode/polymode
  6. ;;
  7. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  8. ;;
  9. ;; This file is *NOT* part of GNU Emacs.
  10. ;;
  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 3, or
  14. ;; (at your option) any later version.
  15. ;;
  16. ;; This program is distributed in the hope that it will be useful,
  17. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. ;; General Public License for more details.
  20. ;;
  21. ;; You should have received a copy of the GNU General Public License
  22. ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
  23. ;;
  24. ;;
  25. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  26. ;;
  27. ;;; Commentary:
  28. ;;
  29. ;;; Code:
  30. ;; FONT-LOCK COMPONENTS:
  31. ;;
  32. ;; All * functions are lazy in poly-lock and jit-lock because they just mark
  33. ;; 'fontified nil.
  34. ;;
  35. ;; fontification-functions -> jit-lock-function / poly-lock-function
  36. ;; font-lock-ensure -> font-lock-ensure-function -> jit-lock-fontify-now/poly-lock-fontify-now
  37. ;; *font-lock-flush -> font-lock-flush-function -> jit-lock-refontify / poly-lock-flush
  38. ;; *font-lock-fontify-buffer -> font-lock-fontify-buffer-function -> jit-lock-refontify / poly-lock-flush
  39. ;; font-lock-fontify-region -> font-lock-fontify-region-function -> font-lock-default-fontify-region
  40. ;; font-lock-unfontify-region -> font-lock-unfontify-region-function -> font-lock-default-unfontify-region
  41. ;; font-lock-unfontify-buffer -> font-lock-unfontify-buffer-function -> font-lock-default-unfontify-buffer
  42. ;;
  43. ;; Jit-lock components:
  44. ;; fontification-functions (called by display engine)
  45. ;; --> jit-lock-function
  46. ;; --> jit-lock-fontify-now (or deferred through timer/text-properties)
  47. ;; --> jit-lock--run-functions
  48. ;; --> jit-lock-functions (font-lock-fontify-region bug-reference-fontify etc.)
  49. ;;
  50. ;;
  51. ;; Poly-lock components:
  52. ;; fontification-functions
  53. ;; --> poly-lock-function
  54. ;; --> poly-lock-fontify-now
  55. ;; --> jit-lock-fontify-now
  56. ;; ...
  57. ;;
  58. ;; `font-lock-mode' call graph:
  59. ;; -> font-lock-function <---- replaced by `poly-lock-mode'
  60. ;; -> font-lock-default-function
  61. ;; -> font-lock-mode-internal
  62. ;; -> font-lock-turn-on-thing-lock
  63. ;; -> font-lock-turn-on-thing-lock
  64. ;; -> (setq font-lock-flush-function jit-lock-refontify)
  65. ;; -> (setq font-lock-ensure-function jit-lock-fontify-now)
  66. ;; -> (setq font-lock-fontify-buffer-function jit-lock-refontify)
  67. ;; -> (jit-lock-register #'font-lock-fontify-region)
  68. ;; -> (add-hook 'jit-lock-functions #'font-lock-fontify-region nil t)
  69. ;; -> jit-lock-mode
  70. (require 'jit-lock)
  71. (require 'polymode-core)
  72. (defvar poly-lock-allow-fontification t)
  73. (defvar poly-lock-allow-background-adjustment t)
  74. (defvar poly-lock-fontification-in-progress nil)
  75. (defvar poly-lock-defer-after-change t)
  76. (defvar-local poly-lock-mode nil)
  77. (eval-when-compile
  78. (defmacro with-buffer-prepared-for-poly-lock (&rest body)
  79. "Execute BODY in current buffer, overriding several variables.
  80. Preserves the `buffer-modified-p' state of the current buffer."
  81. (declare (debug t))
  82. `(let ((inhibit-point-motion-hooks t))
  83. (with-silent-modifications
  84. ,@body))))
  85. ;; FIXME: Can this hack be avoided if poly-lock is registered in
  86. ;; `font-lock-support-mode'?
  87. (defun poly-lock-no-jit-lock-in-polymode-buffers (fun arg)
  88. "Don't activate FUN in `polymode' buffers.
  89. When not in polymode buffers apply FUN to ARG."
  90. (unless polymode-mode
  91. (funcall fun arg)))
  92. (pm-around-advice 'jit-lock-mode #'poly-lock-no-jit-lock-in-polymode-buffers)
  93. ;; see the comment in pm--mode-setup for these
  94. (pm-around-advice 'font-lock-fontify-region #'polymode-inhibit-during-initialization)
  95. (pm-around-advice 'font-lock-fontify-buffer #'polymode-inhibit-during-initialization)
  96. (pm-around-advice 'font-lock-ensure #'polymode-inhibit-during-initialization)
  97. (defun poly-lock-mode (arg)
  98. "This is the value of `font-lock-function' in all polymode buffers.
  99. Mode activated when ARG is positive; happens when font-lock is
  100. switched on."
  101. (unless polymode-mode
  102. (error "Calling `poly-lock-mode' in a non-polymode buffer (%s)" (current-buffer)))
  103. (setq poly-lock-mode arg)
  104. (if arg
  105. (progn
  106. ;; a lot of the following is inspired by what jit-lock does in
  107. ;; `font-lock-turn-on-thing-lock'
  108. (setq-local font-lock-support-mode 'poly-lock-mode)
  109. (setq-local font-lock-dont-widen t)
  110. ;; Re-use jit-lock registration. Some minor modes (adaptive-wrap)
  111. ;; register extra functionality. [Unfortunately `jit-lock-register'
  112. ;; calls `jit-lock-mode' which we don't want. Hence the advice. TOTHINK:
  113. ;; Simply add-hook to `jit-lock-functions'?]
  114. (jit-lock-register 'font-lock-fontify-region)
  115. ;; don't allow other functions
  116. (setq-local fontification-functions '(poly-lock-function))
  117. (setq-local font-lock-flush-function 'poly-lock-flush)
  118. (setq-local font-lock-fontify-buffer-function 'poly-lock-flush)
  119. (setq-local font-lock-ensure-function 'poly-lock-fontify-now)
  120. ;; There are some more, jit-lock doesn't change those, neither do we:
  121. ;; font-lock-unfontify-region-function (defaults to font-lock-default-unfontify-region)
  122. ;; font-lock-unfontify-buffer-function (defualts to font-lock-default-unfontify-buffer)
  123. ;; Don't fontify eagerly (and don't abort if the buffer is large). NB:
  124. ;; `font-lock-flush' is not triggered if this is nil.
  125. (setq-local font-lock-fontified t)
  126. ;; Now we can finally call `font-lock-default-function' because
  127. ;; `font-lock-support-mode' is set to "unrecognizible" value, only core
  128. ;; font-lock setup happens.
  129. (font-lock-default-function arg)
  130. ;; Must happen after call to `font-lock-default-function'
  131. (remove-hook 'after-change-functions 'font-lock-after-change-function t)
  132. (remove-hook 'after-change-functions 'jit-lock-after-change t)
  133. (add-hook 'after-change-functions 'poly-lock-after-change nil t)
  134. ;; Reusing jit-lock var becuase modes populate it directly. We are using
  135. ;; this in `poly-lock-after-change' below. Taken from `jit-lock
  136. ;; initialization.
  137. (add-hook 'jit-lock-after-change-extend-region-functions
  138. 'font-lock-extend-jit-lock-region-after-change
  139. nil t))
  140. (remove-hook 'after-change-functions 'poly-lock-after-change t)
  141. (remove-hook 'fontification-functions 'poly-lock-function t))
  142. (current-buffer))
  143. (defvar poly-lock-chunk-size 2500
  144. "Poly-lock fontifies chunks of at most this many characters at a time.")
  145. (defun poly-lock-function (start)
  146. "The only function in `fontification-functions' in polymode buffers.
  147. This is the entry point called by the display engine. START is
  148. defined in `fontification-functions'. This function has the same
  149. scope as `jit-lock-function'."
  150. (unless pm-initialization-in-progress
  151. (if (and poly-lock-mode (not memory-full))
  152. (unless (input-pending-p)
  153. (let ((end (min (or (text-property-any start (point-max) 'fontified t)
  154. (point-max))
  155. (+ start poly-lock-chunk-size))))
  156. (when (< start end)
  157. (poly-lock-fontify-now start end))))
  158. (with-buffer-prepared-for-poly-lock
  159. (put-text-property start (point-max) 'fontified t)))))
  160. (defun poly-lock-fontify-now (beg end &optional _verbose)
  161. "Polymode main fontification function.
  162. Fontifies chunk-by chunk within the region BEG END."
  163. (unless (or poly-lock-fontification-in-progress
  164. pm-initialization-in-progress)
  165. (let* ((font-lock-dont-widen t)
  166. ;; For now we fontify entire chunks at once. This simplicity is
  167. ;; warranted in multi-mode use cases.
  168. (font-lock-extend-region-functions nil)
  169. ;; Fontification in one buffer can trigger fontification in another
  170. ;; buffer. Particularly, this happens when new indirect buffers are
  171. ;; created and `normal-mode' triggers font-lock in those buffers. We
  172. ;; avoid this by dynamically binding
  173. ;; `poly-lock-fontification-in-progress' and un-setting
  174. ;; `fontification-functions' in case re-display suddenly decides to
  175. ;; fontify something else in other buffer. There are also font-lock
  176. ;; guards in pm--mode-setup.
  177. (poly-lock-fontification-in-progress t)
  178. (fontification-functions nil)
  179. (protect-host (or
  180. (with-current-buffer (pm-base-buffer)
  181. (eieio-oref pm/chunkmode 'protect-font-lock))
  182. ;; HACK: Some inner modes use syntax-table text
  183. ;; property. If there is, for example, a comment
  184. ;; syntax somewhere in the body span, havoc is spelled
  185. ;; in font-lock-fontify-syntactically-region which
  186. ;; calls parse-partial-sexp. For example fortran block
  187. ;; in ../poly-markdown/tests/input/markdown.md. We do
  188. ;; our best and protect the host in such cases.
  189. (/= (next-single-property-change beg 'syntax-table nil end)
  190. end))))
  191. (save-restriction
  192. (widen)
  193. (save-excursion
  194. ;; TEMPORARY HACK: extend to the next span boundary in code blocks
  195. ;; (needed because re-display fontifies by small regions)
  196. (let ((end-span (pm-innermost-span end)))
  197. (if (car end-span)
  198. (when (< (nth 1 end-span) end)
  199. (setq end (nth 2 end-span)))
  200. ;; in host extend to paragraphs as in poly-lock--extend-region
  201. (goto-char end)
  202. (when (search-forward "\n\n" nil t)
  203. (setq end (min (1- (point)) (nth 2 end-span))))))
  204. ;; Fontify the whole region in host first. It's ok for modes like
  205. ;; markdown, org and slim which understand inner mode chunks.
  206. (unless protect-host
  207. (let ((span (pm-innermost-span beg)))
  208. (when (or (null (pm-true-span-type span))
  209. ;; in inner spans fontify only if region is bigger than the span
  210. (< (nth 2 span) end))
  211. (with-current-buffer (pm-base-buffer)
  212. (with-buffer-prepared-for-poly-lock
  213. (when poly-lock-allow-fontification
  214. (put-text-property beg end 'fontified nil) ; just in case
  215. ;; (message "jlrf-host:%d-%d %s" beg end major-mode)
  216. (condition-case-unless-debug err
  217. ;; NB: Some modes fontify beyond the limits (org-mode).
  218. ;; We need a reliably way to detect the actual limit of
  219. ;; the fontification.
  220. (save-restriction
  221. (widen)
  222. (jit-lock--run-functions beg end))
  223. (error
  224. (message "(jit-lock--run-functions %s %s) [UNPR HOST %s]: %s"
  225. beg end (current-buffer) (error-message-string err)))))
  226. (put-text-property beg end 'fontified t))))))
  227. (pm-map-over-spans
  228. (lambda (span)
  229. (when (or (pm-true-span-type span)
  230. protect-host)
  231. (let ((sbeg (nth 1 span))
  232. (send (nth 2 span)))
  233. ;; skip empty spans
  234. (with-buffer-prepared-for-poly-lock
  235. (when (> send sbeg)
  236. (if (not (and poly-lock-allow-fontification
  237. poly-lock-mode))
  238. (put-text-property sbeg send 'fontified t)
  239. (let ((new-beg (max sbeg beg))
  240. (new-end (min send end)))
  241. (put-text-property new-beg new-end 'fontified nil)
  242. ;; (message "jlrf:%d-%d %s" new-beg new-end major-mode)
  243. (condition-case-unless-debug err
  244. (if (eieio-oref pm/chunkmode 'protect-font-lock)
  245. (pm-with-narrowed-to-span span
  246. (jit-lock--run-functions new-beg new-end))
  247. (jit-lock--run-functions new-beg new-end))
  248. (error
  249. (message "(jit-lock--run-functions %s %s) [span %d %d %s] -> (font-lock-default-fontify-region %s %s): %s"
  250. new-beg new-end sbeg send (current-buffer) new-beg new-end
  251. (error-message-string err))))
  252. ;; even if failed set to t
  253. (put-text-property new-beg new-end 'fontified t)))
  254. (when poly-lock-allow-background-adjustment
  255. (poly-lock-adjust-span-face span)))))))
  256. beg end))))
  257. (current-buffer)))
  258. (defun poly-lock-flush (&optional beg end)
  259. "Force refontification of the region BEG..END.
  260. This function is placed in `font-lock-flush-function''"
  261. (unless poly-lock-fontification-in-progress
  262. (let ((beg (or beg (point-min)))
  263. (end (or end (point-max))))
  264. (with-buffer-prepared-for-poly-lock
  265. (save-restriction
  266. (widen)
  267. (pm-flush-span-cache beg end)
  268. (put-text-property beg end 'fontified nil))))))
  269. (defvar jit-lock-start)
  270. (defvar jit-lock-end)
  271. (defun poly-lock--extend-region (beg end)
  272. "Our own extension function which runs first on BEG END change.
  273. Assumes widen buffer. Sets `jit-lock-start' and `jit-lock-end'."
  274. ;; NB: Debug this like
  275. ;; (with-silent-modifications (insert "`") (poly-lock-after-change 65 66 0))
  276. ;; FIXME: this one extends to whole spans; not good. old span can disappear,
  277. ;; shrunk, extend etc
  278. ;; TOCHECK: Pretty surely we need not use 'no-cache here.
  279. ;; With differed after change, any function calling pm-innermost-span (mostly
  280. ;; syntax-propertize) will reset the spans, so the extension relying on
  281. ;; :pm-span cache will not detect the change. Use instead the especially setup
  282. ;; for this purpose :pm-span-old cache in poly-lock-after-change.
  283. (let* ((prop-name (if poly-lock-defer-after-change :pm-span-old :pm-span))
  284. (old-beg (or (previous-single-property-change beg prop-name)
  285. (point-min)))
  286. (old-end (or (next-single-property-change end prop-name)
  287. (point-max)))
  288. ;; need this here before pm-innermost-span call
  289. (old-beg-obj (nth 3 (get-text-property old-beg prop-name)))
  290. (beg-span (pm-innermost-span beg 'no-cache))
  291. (end-span (if (<= end (nth 2 beg-span))
  292. beg-span
  293. (pm-innermost-span end 'no-cache)))
  294. (sbeg (nth 1 beg-span))
  295. (send (nth 2 end-span)))
  296. (if (< old-beg sbeg)
  297. (let ((new-beg-span (pm-innermost-span old-beg)))
  298. (if (eq old-beg-obj (nth 3 new-beg-span)) ; old-beg == (nth 1 new-beg-span) for sure
  299. ;; new span appeared within an old span, don't refontify the old part (common case)
  300. (setq jit-lock-start (min sbeg (nth 2 new-beg-span)))
  301. ;; wrong span shrunk to its correct size (rare or never)
  302. (setq jit-lock-start old-beg)))
  303. ;; refontify the entire new span
  304. (setq jit-lock-start sbeg))
  305. ;; (dbg (pm-format-span beg-span))
  306. ;; always include head
  307. (when (and (eq (car beg-span) 'tail)
  308. (> jit-lock-start (point-min)))
  309. (setq jit-lock-start (nth 1 (pm-innermost-span (1- jit-lock-start)))))
  310. (when (and (eq (car beg-span) 'body)
  311. (> jit-lock-start (point-min)))
  312. (setq jit-lock-start (nth 1 (pm-innermost-span (1- jit-lock-start)))))
  313. ;; I think it's not possible to do better than this. When region is shrunk,
  314. ;; previous region could be incorrectly fontified even if the mode is
  315. ;; preserved due to wrong ppss
  316. (setq jit-lock-end (max send old-end))
  317. ;; Check if the type of following span changed (for example when
  318. ;; modification is in head of an auto-chunk). Do this repeatedly till no
  319. ;; change. [TOTHINK: Do we need similar extension backwards?]
  320. (let ((go-on t))
  321. (while (and (< jit-lock-end (point-max))
  322. go-on)
  323. (let ((ospan (get-text-property jit-lock-end prop-name))
  324. (nspan (pm-innermost-span jit-lock-end 'no-cache)))
  325. ;; (dbg "N" (pm-format-span nspan))
  326. ;; (dbg "O" (pm-format-span ospan))
  327. ;; if spans have just been moved by buffer modification, stop
  328. (if ospan
  329. (if (and (eq (nth 3 nspan) (nth 3 ospan))
  330. (= (- (nth 2 nspan) (nth 1 nspan))
  331. (- (nth 2 ospan) (nth 1 ospan))))
  332. (setq go-on nil)
  333. (setq jit-lock-end (nth 2 nspan)
  334. end-span nspan))
  335. (setq go-on nil
  336. jit-lock-end (point-max))))))
  337. ;; This extension is needed because some host modes (org) either don't
  338. ;; fontify the head correctly when tail is not there or worse, fontify
  339. ;; larger spans than asked for. It's mostly for unprotected hosts, but
  340. ;; doing it here for all cases to err on the safe side.
  341. ;; always include body of the head
  342. (when (and (eq (car end-span) 'head)
  343. (< jit-lock-end (point-max)))
  344. (setq end-span (pm-innermost-span jit-lock-end)
  345. jit-lock-end (nth 2 end-span)))
  346. ;; always include tail
  347. (when (and (eq (car end-span) 'body)
  348. (< jit-lock-end (point-max)))
  349. (setq jit-lock-end (nth 2 (pm-innermost-span jit-lock-end))
  350. end-span (pm-innermost-span jit-lock-end)))
  351. ;; Temporary hack for large host mode chunks - narrow to empty lines
  352. (when (> (* 2 poly-lock-chunk-size)
  353. (- jit-lock-end jit-lock-start))
  354. (when (eq (car beg-span) nil)
  355. (let ((tbeg (min beg (nth 2 beg-span))))
  356. (when (> (- tbeg jit-lock-start) poly-lock-chunk-size)
  357. (goto-char (- tbeg poly-lock-chunk-size))
  358. (when (search-backward "\n\n" nil t)
  359. (setq jit-lock-start (max jit-lock-start (1+ (point))))))))
  360. (when (eq (car end-span) nil)
  361. (let ((tend (max end (nth 1 end-span))))
  362. (when (> (- jit-lock-end tend) poly-lock-chunk-size)
  363. (goto-char (+ tend poly-lock-chunk-size))
  364. (when (search-forward "\n\n" nil t)
  365. (setq jit-lock-end (min jit-lock-end (1- (point)))))))))
  366. (cons jit-lock-start jit-lock-end)))
  367. ;; (defun poly-lock--jit-lock-extend-region-span (span old-len)
  368. ;; "Call `jit-lock-after-change-extend-region-functions' protected to SPAN.
  369. ;; Extend `jit-lock-start' and `jit-lock-end' by side effect.
  370. ;; OLD-LEN is passed to the extension function."
  371. ;; ;; FIXME: for multi-span regions this function seems to reset
  372. ;; ;; jit-lock-start/end to spans limits
  373. ;; (let ((beg jit-lock-start)
  374. ;; (end jit-lock-end))
  375. ;; (let ((sbeg (nth 1 span))
  376. ;; (send (nth 2 span)))
  377. ;; (when (or (> beg sbeg) (< end send))
  378. ;; (pm-with-narrowed-to-span span
  379. ;; (setq jit-lock-start (max beg sbeg)
  380. ;; jit-lock-end (min end send))
  381. ;; (condition-case err
  382. ;; (progn
  383. ;; ;; set jit-lock-start and jit-lock-end by side effect
  384. ;; (run-hook-with-args 'jit-lock-after-change-extend-region-functions
  385. ;; jit-lock-start jit-lock-end old-len))
  386. ;; (error (message "(after-change-extend-region-functions %s %s %s) -> %s"
  387. ;; jit-lock-start jit-lock-end old-len
  388. ;; (error-message-string err))))
  389. ;; ;; FIXME: this is not in the right buffer, we need to do it in the
  390. ;; ;; original buffer.
  391. ;; (setq jit-lock-start (min beg (max jit-lock-start sbeg))
  392. ;; jit-lock-end (max end (min jit-lock-end send))))
  393. ;; (cons jit-lock-start jit-lock-end)))))
  394. (defvar-local poly-lock--timer nil)
  395. (defvar-local poly-lock--beg-change most-positive-fixnum)
  396. (defvar-local poly-lock--end-change most-negative-fixnum)
  397. (defun poly-lock--after-change-internal (buffer _old-len)
  398. (when (buffer-live-p buffer)
  399. (with-current-buffer buffer
  400. (setq poly-lock--timer nil)
  401. ;; FIXME: timers can overlap; remove this check with global timer
  402. (when (> poly-lock--end-change 0)
  403. (with-buffer-prepared-for-poly-lock
  404. (save-excursion
  405. (save-restriction
  406. (widen)
  407. (let ((beg poly-lock--beg-change)
  408. (end (min (point-max) poly-lock--end-change)))
  409. (setq poly-lock--beg-change most-positive-fixnum
  410. poly-lock--end-change most-negative-fixnum)
  411. (save-match-data
  412. (poly-lock--extend-region beg end)
  413. ;; no need for 'no-cache; poly-lock--extend-region re-computed the spans
  414. ;; FIXME: currently poly-lock--extend-region extends to whole
  415. ;; spans, which could get crazy for very large chunks, but
  416. ;; seems to work really well with the deferred after-change
  417. ;; hook. So the following jit-lock extensions are not needed
  418. ;; and probably even harm.
  419. ;; This extension hooks are run for major-mode's syntactic
  420. ;; hacks mostly and not that much for actual extension. For
  421. ;; example, markdown can syntactically propertize in this hook
  422. ;; markdown-font-lock-extend-region-function. Call on the
  423. ;; entire region host hooks to account for such patterns.
  424. ;; (let ((hostmode (oref pm/polymode -hostmode)))
  425. ;; (unless (eieio-oref hostmode 'protect-font-lock)
  426. ;; (with-current-buffer (pm-base-buffer)
  427. ;; (run-hook-with-args 'jit-lock-after-change-extend-region-functions
  428. ;; beg end old-len)
  429. ;; (setq beg jit-lock-start
  430. ;; end jit-lock-end)))
  431. ;; (let ((bspan (pm-innermost-span jit-lock-start)))
  432. ;; ;; FIXME: these are currently always protected and set
  433. ;; ;; jit-lock-end/start in their own buffers, not the buffer
  434. ;; ;; which invoked the after-change-hook
  435. ;; (unless (eq (nth 3 bspan) hostmode)
  436. ;; (poly-lock--jit-lock-extend-region-span bspan old-len))
  437. ;; (when (< (nth 2 bspan) jit-lock-end)
  438. ;; (let ((espan (pm-innermost-span jit-lock-end)))
  439. ;; (unless (eq (nth 3 espan) hostmode)
  440. ;; (poly-lock--jit-lock-extend-region-span espan old-len)))))
  441. ;; )
  442. ;; ;; Why is this still needed? poly-lock--extend-region re-computes the spans
  443. ;; (pm-flush-span-cache jit-lock-start jit-lock-end)
  444. ;; (dbg (cb) jit-lock-start jit-lock-end)
  445. ;; (put-text-property jit-lock-end jit-lock-end :poly-lock-refontify nil)
  446. (put-text-property jit-lock-start jit-lock-end 'fontified nil))))))))))
  447. (defun poly-lock-after-change (beg end old-len)
  448. "Mark changed region with 'fontified nil.
  449. Extend the region to spans which need to be updated. BEG, END and
  450. OLD-LEN are as in `after-change-functions'. When
  451. `poly-lock-defer-after-change' is non-nil (the default), run fontification"
  452. (when (and poly-lock-mode
  453. pm-allow-after-change-hook
  454. (not memory-full))
  455. ;; Extension is slow but after-change functions can be called in rapid
  456. ;; succession (#200 with string-rectangle on which combine-change-calls is
  457. ;; of little help). Thus we do that in a timer.
  458. (when (timerp poly-lock--timer)
  459. ;; FIXME: Instead of local timer, make a global one iterating over
  460. ;; relevant buffers
  461. (cancel-timer poly-lock--timer))
  462. (if poly-lock-defer-after-change
  463. (progn
  464. (with-silent-modifications
  465. ;; don't re-fontify before we extend
  466. (put-text-property beg end 'fontified t)
  467. (setq poly-lock--beg-change (min beg end poly-lock--beg-change)
  468. poly-lock--end-change (max beg end poly-lock--end-change))
  469. ;; between this call and deferred extension pm-inner-span can be
  470. ;; called, so we cache a few :pm-span properties around beg/end
  471. (poly-lock--cache-pm-span-property beg end))
  472. (setq-local poly-lock--timer
  473. (run-at-time 0.05 nil #'poly-lock--after-change-internal
  474. (current-buffer) old-len)))
  475. (setq poly-lock--beg-change beg
  476. poly-lock--end-change end)
  477. (poly-lock--after-change-internal (current-buffer) old-len))))
  478. (defun poly-lock--cache-pm-span-property (beg end)
  479. ;; cache one previous and 5 forward spans
  480. (let ((new-beg (or (previous-single-property-change beg :pm-span)
  481. (point-min))))
  482. (put-text-property new-beg beg :pm-span-old (get-text-property new-beg :pm-span)))
  483. (let ((i 5))
  484. (while (and (< 0 i) (< end (point-max)))
  485. (let ((new-end (or (next-single-property-change end :pm-span)
  486. (point-max))))
  487. (put-text-property new-end end :pm-span-old (get-text-property (1- new-end) :pm-span))
  488. (setq end new-end
  489. i (1- i))))))
  490. (defun poly-lock--adjusted-background (prop)
  491. ;; if > lighten on dark backgroun. Oposite on light.
  492. (color-lighten-name (face-background 'default)
  493. (if (eq (frame-parameter nil 'background-mode) 'light)
  494. (- prop) ;; darken
  495. prop)))
  496. (declare-function pm-get-adjust-face "polymode-methods")
  497. (defvar poly-lock--extra-span-props (when (fboundp 'set-face-extend) (list :extend t)))
  498. (defun poly-lock-adjust-span-face (span)
  499. "Adjust 'face property of SPAN..
  500. How adjustment is made is defined in :adjust-face slot of the
  501. SPAN's chunkmode."
  502. (interactive "r")
  503. (let ((face (pm-get-adjust-face (nth 3 span) (car span))))
  504. (let ((face (if (numberp face)
  505. (unless (= face 0)
  506. (list (append (list :background (poly-lock--adjusted-background face))
  507. poly-lock--extra-span-props)))
  508. face)))
  509. (when face
  510. (font-lock-append-text-property
  511. (nth 1 span) (nth 2 span) 'face face)))))
  512. (provide 'poly-lock)
  513. ;;; poly-lock.el ends here