Mercurial > emacs
comparison lisp/lazy-lock.el @ 15461:a0dc879461b8
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Wed, 19 Jun 1996 23:14:13 +0000 |
parents | |
children | aa9675ed8ed4 |
comparison
equal
deleted
inserted
replaced
15460:be07c4433554 | 15461:a0dc879461b8 |
---|---|
1 ;;; lazy-lock.el --- Lazy demand-driven fontification for fast Font Lock mode. | |
2 | |
3 ;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Simon Marshall <simon@gnu.ai.mit.edu> | |
6 ;; Keywords: faces files | |
7 ;; Version: 2.05 | |
8 | |
9 ;;; This file is part of GNU Emacs. | |
10 | |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
12 ;; it under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; GNU Emacs 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 | |
19 ;; GNU 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; see the file COPYING. If not, write to the | |
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 ;; Boston, MA 02111-1307, USA. | |
25 | |
26 ;;; Commentary: | |
27 | |
28 ;; Purpose: | |
29 ;; | |
30 ;; To make visiting buffers in `font-lock-mode' faster by making fontification | |
31 ;; be demand-driven, deferred and stealthy. | |
32 ;; Fontification only occurs when, and where, necessary. | |
33 ;; | |
34 ;; See caveats and feedback below. | |
35 ;; See also the fast-lock package. (But don't use them at the same time!) | |
36 | |
37 ;; Installation: | |
38 ;; | |
39 ;; Put in your ~/.emacs: | |
40 ;; | |
41 ;; (autoload 'turn-on-lazy-lock "lazy-lock" | |
42 ;; "Unconditionally turn on Lazy Lock mode.") | |
43 ;; | |
44 ;; (add-hook 'font-lock-mode-hook 'turn-on-lazy-lock) | |
45 ;; | |
46 ;; Start up a new Emacs and use font-lock as usual (except that you can use the | |
47 ;; so-called "gaudier" fontification regexps on big files without frustration). | |
48 ;; | |
49 ;; In a buffer (which has `font-lock-mode' enabled) which is at least | |
50 ;; `lazy-lock-minimum-size' characters long, buffer fontification will not | |
51 ;; occur and only the visible portion of the buffer will be fontified. Motion | |
52 ;; around the buffer will fontify those visible portions not previously | |
53 ;; fontified. If stealth fontification is enabled, buffer fontification will | |
54 ;; occur in invisible parts of the buffer after `lazy-lock-stealth-time' | |
55 ;; seconds of idle time. If on-the-fly fontification is deferred, on-the-fly | |
56 ;; fontification will occur after `lazy-lock-defer-time' seconds of idle time. | |
57 | |
58 ;; User-visible differences with version 1: | |
59 ;; | |
60 ;; - Version 2 can defer on-the-fly fontification. Therefore you need not, and | |
61 ;; should not, use defer-lock.el with this version of lazy-lock.el. | |
62 ;; | |
63 ;; A number of variables have changed meaning: | |
64 ;; | |
65 ;; - A value of nil for the variable `lazy-lock-minimum-size' means never turn | |
66 ;; on demand-driven fontification. In version 1 this meant always turn on | |
67 ;; demand-driven fontification. If you really want demand-driven fontification | |
68 ;; regardless of buffer size, set this variable to 0. | |
69 ;; | |
70 ;; - The variable `lazy-lock-stealth-lines' cannot have a nil value. In | |
71 ;; version 1 this meant use `window-height' as the maximum number of lines to | |
72 ;; fontify as a stealth chunk. This makes no sense; stealth fontification is | |
73 ;; of a buffer, not a window. | |
74 | |
75 ;; Implementation differences with version 1: | |
76 ;; | |
77 ;; - Version 1 of lazy-lock.el is a bit of a hack. Version 1 demand-driven | |
78 ;; fontification, the core feature of lazy-lock.el, is implemented by placing a | |
79 ;; function on `post-command-hook'. This function fontifies where necessary, | |
80 ;; i.e., where a window scroll has occurred. However, there are a number of | |
81 ;; problems with using `post-command-hook': | |
82 ;; | |
83 ;; (a) As the name suggests, `post-command-hook' is run after every command, | |
84 ;; i.e., frequently and regardless of whether scrolling has occurred. | |
85 ;; (b) Scrolling can occur during a command, when `post-command-hook' is not | |
86 ;; run, i.e., it is not necessarily run after scrolling has occurred. | |
87 ;; (c) When `post-command-hook' is run, there is nothing to suggest where | |
88 ;; scrolling might have occurred, i.e., which windows have scrolled. | |
89 ;; | |
90 ;; Thus lazy-lock.el's function is called almost as often as possible, usually | |
91 ;; when it need not be called, yet it is not always called when it is needed. | |
92 ;; Also, lazy-lock.el's function must check each window to see if a scroll has | |
93 ;; occurred there. Worse still, lazy-lock.el's function must fontify a region | |
94 ;; twice as large as necessary to make sure the window is completely fontified. | |
95 ;; Basically, `post-command-hook' is completely inappropriate for lazy-lock.el. | |
96 ;; | |
97 ;; Ideally, we want to attach lazy-lock.el's function to a hook that is run | |
98 ;; only when scrolling occurs, e.g., `window-start' has changed, and tells us | |
99 ;; as much information as we need, i.e., the window and its new buffer region. | |
100 ;; Richard Stallman implemented a `window-scroll-functions' for Emacs 19.30. | |
101 ;; Functions on it are run when `window-start' has changed, and are supplied | |
102 ;; with the window and the window's new `window-start' position. (It would be | |
103 ;; better if it also supplied the window's new `window-end' position, but that | |
104 ;; is calculated as part of the redisplay process, and the functions on | |
105 ;; `window-scroll-functions' are run before redisplay has finished.) Thus, the | |
106 ;; hook deals with the above problems (a), (b) and (c). | |
107 ;; | |
108 ;; If only life was that easy. Version 2 demand-driven fontification is mostly | |
109 ;; implemented by placing a function on `window-scroll-functions'. However, | |
110 ;; not all scrolling occurs when `window-start' has changed. A change in | |
111 ;; window size, e.g., via C-x 1, or a significant deletion, e.g., of a number | |
112 ;; of lines, causes `window-end' to change without changing `window-start'. | |
113 ;; Arguably, these events are not scrolling events, but fontification must | |
114 ;; occur for lazy-lock.el to work. Hooks `window-size-change-functions' and | |
115 ;; `redisplay-end-trigger-functions' were added for these circumstances. | |
116 ;; | |
117 ;; Ben Wing thinks these hooks are "horribly horribly kludgy", and implemented | |
118 ;; a `pre-idle-hook', a `mother-of-all-post-command-hooks', for XEmacs 19.14. | |
119 ;; He then hacked up a version 1 lazy-lock.el to use `pre-idle-hook' rather | |
120 ;; than `post-command-hook'. Whereas functions on `post-command-hook' are | |
121 ;; called almost as often as possible, functions on `pre-idle-hook' really are | |
122 ;; called as often as possible, even when the mouse moves and, on some systems, | |
123 ;; while XEmacs is idle. Thus, the hook deals with the above problem (b), but | |
124 ;; unfortunately it makes (a) worse and does not address (c) at all. | |
125 ;; | |
126 ;; I freely admit that `redisplay-end-trigger-functions' and, to a much lesser | |
127 ;; extent, `window-size-change-functions' are not pretty. However, I feel that | |
128 ;; a `window-scroll-functions' feature is cleaner than a `pre-idle-hook', and | |
129 ;; the result is faster and smaller, less intrusive and more targeted, code. | |
130 ;; Since `pre-idle-hook' is pretty much like `post-command-hook', there is no | |
131 ;; point in making this version of lazy-lock.el work with it. Anyway, that's | |
132 ;; Lit 30 of my humble opinion. | |
133 ;; | |
134 ;; - Version 1 stealth fontification is also implemented by placing a function | |
135 ;; on `post-command-hook'. This function waits for a given amount of time, | |
136 ;; and, if Emacs remains idle, fontifies where necessary. Again, there are a | |
137 ;; number of problems with using `post-command-hook': | |
138 ;; | |
139 ;; (a) Functions on `post-command-hook' are run sequentially, so this function | |
140 ;; can interfere with other functions on the hook, and vice versa. | |
141 ;; (b) This function waits for a given amount of time, so it can interfere with | |
142 ;; various features that are dealt with by Emacs after a command, e.g., | |
143 ;; region highlighting, asynchronous updating and keystroke echoing. | |
144 ;; (c) Fontification may be required during a command, when `post-command-hook' | |
145 ;; is not run. (Version 2 deferred fontification only.) | |
146 ;; | |
147 ;; Again, `post-command-hook' is completely inappropriate for lazy-lock.el. | |
148 ;; Richard Stallman and Morten Welinder implemented internal Timers and Idle | |
149 ;; Timers for Emacs 19.31. Functions can be run independently at given times | |
150 ;; or after given amounts of idle time. Thus, the feature deals with the above | |
151 ;; problems (a), (b) and (c). Version 2 deferral and stealth are implemented | |
152 ;; by functions on Idle Timers. (A function on XEmacs' `pre-idle-hook' is | |
153 ;; similar to an Emacs Idle Timer function with a fixed zero second timeout. | |
154 ;; Hey, maybe I could stop using `window-scroll-functions' for demand-driven | |
155 ;; fontification and use a zero second Emacs Idle Timer instead? Only joking!) | |
156 | |
157 ;; Caveats: | |
158 ;; | |
159 ;; Lazy Lock mode does not work efficiently with Outline mode. This is because | |
160 ;; when in Outline mode, although text may be hidden (not visible in the | |
161 ;; window), the text is visible to Emacs Lisp code (not surprisingly) and Lazy | |
162 ;; Lock fontifies it mercilessly. Hopefully this will be fixed one day. | |
163 ;; | |
164 ;; Because buffer text is not necessarily fontified, other packages that expect | |
165 ;; buffer text to be fontified in Font Lock mode either might not work as | |
166 ;; expected, or might not display buffer text as expected. An example of the | |
167 ;; latter is `occur', which copies lines of buffer text into another buffer. | |
168 ;; | |
169 ;; In Emacs 19.30, Lazy Lock mode does not ensure that an existing buffer is | |
170 ;; fontified if it is made visible via a minibuffer-less command that replaces | |
171 ;; an existing window's buffer (e.g., via the Buffers menu). Upgrade! | |
172 ;; | |
173 ;; In Emacs 19.30, Lazy Lock mode does not work well with Transient Mark mode | |
174 ;; or modes based on Comint mode (e.g., Shell mode), and also interferes with | |
175 ;; the echoing of keystrokes in the minibuffer. This is because of the way | |
176 ;; deferral and stealth have to be implemented for Emacs 19.30. Upgrade! | |
177 ;; | |
178 ;; Currently XEmacs does not have the features to support lazy-lock.el. Maybe | |
179 ;; it will one day. | |
180 | |
181 ;; Feedback: | |
182 ;; | |
183 ;; Feedback is welcome. | |
184 ;; To submit a bug report (or make comments) please use the mechanism provided: | |
185 ;; | |
186 ;; M-x lazy-lock-submit-bug-report RET | |
187 | |
188 ;; History: | |
189 ;; | |
190 ;; 1.15--2.00: | |
191 ;; - Rewrite for Emacs 19.30 and the features rms added to support lazy-lock.el | |
192 ;; so that it could work correctly and efficiently. | |
193 ;; - Many thanks to those who reported bugs, fixed bugs, made suggestions or | |
194 ;; otherwise contributed in the version 1 cycle; Jari Aalto, Kevin Broadey, | |
195 ;; Ulrik Dickow, Bill Dubuque, Bob Glickstein, Boris Goldowsky, | |
196 ;; Jonas Jarnestrom, David Karr, Michael Kifer, Erik Naggum, Rick Sladkey, | |
197 ;; Jim Thompson, Ben Wing, Ilya Zakharevich, and Richard Stallman. | |
198 ;; 2.00--2.01: | |
199 ;; - Made `lazy-lock-fontify-after-command' always `sit-for' and so redisplay | |
200 ;; - Use `buffer-name' not `buffer-live-p' (Bill Dubuque hint) | |
201 ;; - Made `lazy-lock-install' do `add-to-list' not `setq' of `current-buffer' | |
202 ;; - Made `lazy-lock-fontify-after-install' loop over buffer list | |
203 ;; - Made `lazy-lock-arrange-before-change' to arrange `window-end' triggering | |
204 ;; - Made `lazy-lock-let-buffer-state' wrap both `befter-change-functions' | |
205 ;; - Made `lazy-lock-fontify-region' do `condition-case' (Hyman Rosen report) | |
206 ;; 2.01--2.02: | |
207 ;; - Use `buffer-live-p' as `buffer-name' can barf (Richard Stanton report) | |
208 ;; - Made `lazy-lock-install' set `font-lock-fontified' (Kevin Davidson report) | |
209 ;; - Made `lazy-lock-install' add hooks only if needed | |
210 ;; - Made `lazy-lock-unstall' add `font-lock-after-change-function' if needed | |
211 ;; 2.02--2.03: | |
212 ;; - Made `lazy-lock-fontify-region' do `condition-case' for `quit' too | |
213 ;; - Made `lazy-lock-mode' respect the value of `font-lock-inhibit-thing-lock' | |
214 ;; - Added `lazy-lock-after-unfontify-buffer' | |
215 ;; - Removed `lazy-lock-fontify-after-install' hack | |
216 ;; - Made `lazy-lock-fontify-after-scroll' not `set-buffer' to `window-buffer' | |
217 ;; - Made `lazy-lock-fontify-after-trigger' not `set-buffer' to `window-buffer' | |
218 ;; - Made `lazy-lock-fontify-after-idle' be interruptible (Scott Burson hint) | |
219 ;; 2.03--2.04: | |
220 ;; - Rewrite for Emacs 19.31 idle timers | |
221 ;; - Renamed `buffer-windows' to `get-buffer-window-list' | |
222 ;; - Removed `buffer-live-p' | |
223 ;; - Made `lazy-lock-defer-after-change' always save `current-buffer' | |
224 ;; - Made `lazy-lock-fontify-after-defer' just process buffers | |
225 ;; - Made `lazy-lock-install-hooks' add hooks correctly (Kevin Broadey report) | |
226 ;; - Made `lazy-lock-install' cope if `lazy-lock-defer-time' is a list | |
227 ;; 2.04--2.05: | |
228 ;; - Rewrite for Common Lisp macros | |
229 ;; - Added `do-while' macro | |
230 ;; - Renamed `lazy-lock-let-buffer-state' macro to `save-buffer-state' | |
231 ;; - Returned `lazy-lock-fontify-after-install' hack (Darren Hall hint) | |
232 ;; - Added `lazy-lock-defer-driven' functionality (Scott Byer hint) | |
233 ;; - Made `lazy-lock-mode' wrap `font-lock-support-mode' | |
234 | |
235 (require 'font-lock) | |
236 | |
237 ;; Make sure lazy-lock.el is supported. | |
238 (if (if (save-match-data (string-match "Lucid\\|XEmacs" (emacs-version))) | |
239 t | |
240 (and (= emacs-major-version 19) (< emacs-minor-version 30))) | |
241 (error "`lazy-lock' was written for Emacs 19.30 or later")) | |
242 | |
243 ;; Flush out those lusers who didn't read all of the Commentary. | |
244 (if (or (memq 'turn-on-defer-lock font-lock-mode-hook) | |
245 (memq 'defer-lock-mode font-lock-mode-hook)) | |
246 (error "`lazy-lock' was written for use without `defer-lock'")) | |
247 | |
248 (eval-when-compile | |
249 ;; | |
250 ;; We don't do this at the top-level as idle timers are not necessarily used. | |
251 (require 'timer) | |
252 ;; We don't do this at the top-level as we only use non-autoloaded macros. | |
253 (require 'cl) | |
254 ;; | |
255 ;; Well, shouldn't Lazy Lock mode be as lazy as possible? | |
256 (setq byte-compile-dynamic t byte-compile-dynamic-docstrings t) | |
257 ;; But, we make sure that the code is as zippy as can be. | |
258 (setq byte-optimize t) | |
259 ;; | |
260 ;; We use this to preserve or protect things when modifying text properties. | |
261 (defmacro save-buffer-state (varlist &rest body) | |
262 "Bind variables according to VARLIST and eval BODY restoring buffer state." | |
263 (` (let* ((,@ (append varlist | |
264 '((modified (buffer-modified-p)) | |
265 (inhibit-read-only t) (buffer-undo-list t) | |
266 before-change-functions after-change-functions | |
267 deactivate-mark buffer-file-name buffer-file-truename)))) | |
268 (,@ body) | |
269 (when (and (not modified) (buffer-modified-p)) | |
270 (set-buffer-modified-p nil))))) | |
271 (put 'save-buffer-state 'lisp-indent-function 1) | |
272 ;; | |
273 ;; We use this for clarity and speed. Naughty but nice. | |
274 (defmacro do-while (test &rest body) | |
275 "(do-while TEST BODY...): eval BODY... and repeat if TEST yields non-nil. | |
276 The order of execution is thus BODY, TEST, BODY, TEST and so on | |
277 until TEST returns nil." | |
278 (` (while (progn (,@ body) (, test))))) | |
279 (put 'do-while 'lisp-indent-function (get 'while 'lisp-indent-function))) | |
280 | |
281 ;; User Variables: | |
282 | |
283 (defvar lazy-lock-minimum-size (* 25 1024) | |
284 "*Minimum size of a buffer for demand-driven fontification. | |
285 On-demand fontification occurs if the buffer size is greater than this value. | |
286 If nil, means demand-driven fontification is never performed. | |
287 If a list, each element should be a cons pair of the form (MAJOR-MODE . SIZE), | |
288 where MAJOR-MODE is a symbol or t (meaning the default). For example: | |
289 ((c-mode . 25600) (c++-mode . 25600) (rmail-mode . 1048576)) | |
290 means that the minimum size is 25K for buffers in C or C++ modes, one megabyte | |
291 for buffers in Rmail mode, and size is irrelevant otherwise. | |
292 | |
293 The value of this variable is used when Lazy Lock mode is turned on.") | |
294 | |
295 (defvar lazy-lock-defer-driven nil | |
296 "*If non-nil, means fontification should be defer-driven. | |
297 If nil, means demand-driven fontification is performed. This means when the | |
298 window scrolls into unfontified areas of the buffer, those areas are | |
299 immediately fontified. Thus scrolling never presents unfontified areas. | |
300 However, since fontification occurs during scrolling, scrolling may be slow. | |
301 If t, means defer-driven fontification is performed. This means fontification | |
302 of those areas is deferred. Thus scrolling may present momentarily unfontified | |
303 areas. However, since fontification does not occur during scrolling, scrolling | |
304 will be faster than demand-driven fontification. | |
305 If non-nil and non-t, means buffer demand-driven fontification is performed | |
306 until the buffer is fontified, then buffer fontification becomes defer-driven. | |
307 Thus scrolling never presents unfontified areas until the buffer is fontified, | |
308 at which point subsequent scrolling may present future buffer insertions | |
309 momentarily unfontified. However, since fontification does not occur during | |
310 scrolling once the buffer is fontified, scrolling will become faster. | |
311 | |
312 The value of this variable is used when Lazy Lock mode is turned on.") | |
313 | |
314 (defvar lazy-lock-defer-time | |
315 (if (featurep 'lisp-float-type) (/ (float 1) (float 4)) 1) | |
316 "*Time in seconds to delay before beginning deferred fontification. | |
317 Deferred fontification occurs if there is no input within this time. | |
318 If nil, means fontification is never deferred. However, fontification occurs | |
319 on-the-fly or during scrolling, which may be slow. | |
320 If a list, it should be of the form (MAJOR-MODES . TIME), where MAJOR-MODES is | |
321 a list of `major-mode' symbols for which deferred fontification should occur. | |
322 The sense of the list is negated if it begins with `not'. For example: | |
323 ((c-mode c++-mode) . 0.25) | |
324 means that the deferral time is 0.25s for buffers in C or C++ modes, and | |
325 deferral does not occur otherwise. | |
326 | |
327 The value of this variable is used when Lazy Lock mode is turned on.") | |
328 | |
329 (defvar lazy-lock-stealth-time 30 | |
330 "*Time in seconds to delay before beginning stealth fontification. | |
331 Stealth fontification occurs if there is no input within this time. | |
332 If nil, means stealth fontification is never performed. | |
333 | |
334 The value of this variable is used when Lazy Lock mode is turned on.") | |
335 | |
336 (defvar lazy-lock-stealth-lines (if font-lock-maximum-decoration 100 200) | |
337 "*Maximum size of a chunk of stealth fontification. | |
338 Each iteration of stealth fontification can fontify this number of lines. | |
339 To speed up input response during stealth fontification, at the cost of stealth | |
340 taking longer to fontify, you could reduce the value of this variable.") | |
341 | |
342 (defvar lazy-lock-stealth-nice | |
343 (if (featurep 'lisp-float-type) (/ (float 1) (float 8)) 1) | |
344 "*Time in seconds to pause between chunks of stealth fontification. | |
345 Each iteration of stealth fontification is separated by this amount of time. | |
346 To reduce machine load during stealth fontification, at the cost of stealth | |
347 taking longer to fontify, you could increase the value of this variable.") | |
348 | |
349 (defvar lazy-lock-stealth-verbose font-lock-verbose | |
350 "*If non-nil, means stealth fontification should show status messages.") | |
351 | |
352 (defvar lazy-lock-mode nil) | |
353 (defvar lazy-lock-buffers nil) ; for deferral | |
354 (defvar lazy-lock-timers (cons nil nil)) ; for deferral and stealth | |
355 | |
356 ;; User Functions: | |
357 | |
358 ;;;###autoload | |
359 (defun lazy-lock-mode (&optional arg) | |
360 "Toggle Lazy Lock mode. | |
361 With arg, turn Lazy Lock mode on if and only if arg is positive. Enable it | |
362 automatically in your `~/.emacs' by: | |
363 | |
364 (setq font-lock-support-mode 'lazy-lock-mode) | |
365 | |
366 When Lazy Lock mode is enabled, fontification can be lazy in a number of ways: | |
367 | |
368 - Demand-driven buffer fontification if `lazy-lock-minimum-size' is non-nil. | |
369 This means initial fontification does not occur if the buffer is greater | |
370 than `lazy-lock-minimum-size' characters in length. Instead, fontification | |
371 occurs when necessary, such as when scrolling through the buffer would | |
372 otherwise reveal unfontified areas. This is useful if buffer fontification | |
373 is too slow for large buffers. | |
374 | |
375 - Defer-driven buffer fontification if `lazy-lock-defer-driven' is non-nil. | |
376 This means all fontification is deferred, such as fontification that occurs | |
377 when scrolling through the buffer would otherwise reveal unfontified areas. | |
378 Instead, these areas are seen momentarily unfontified. This is useful if | |
379 demand-driven fontification is too slow to keep up with scrolling. | |
380 | |
381 - Deferred on-the-fly fontification if `lazy-lock-defer-time' is non-nil. | |
382 This means on-the-fly fontification does not occur as you type. Instead, | |
383 fontification is deferred until after `lazy-lock-defer-time' seconds of | |
384 Emacs idle time, while Emacs remains idle. This is useful if on-the-fly | |
385 fontification is too slow to keep up with your typing. | |
386 | |
387 - Stealthy buffer fontification if `lazy-lock-stealth-time' is non-nil. | |
388 This means remaining unfontified areas of buffers are fontified if Emacs has | |
389 been idle for `lazy-lock-stealth-time' seconds, while Emacs remains idle. | |
390 This is useful if any buffer has demand- or defer-driven fontification. | |
391 | |
392 See also variables `lazy-lock-stealth-lines', `lazy-lock-stealth-nice' and | |
393 `lazy-lock-stealth-verbose' for stealth fontification. | |
394 | |
395 Use \\[lazy-lock-submit-bug-report] to send bug reports or feedback." | |
396 (interactive "P") | |
397 (set (make-local-variable 'lazy-lock-mode) | |
398 (and (not (memq 'lazy-lock-mode font-lock-inhibit-thing-lock)) | |
399 (if arg (> (prefix-numeric-value arg) 0) (not lazy-lock-mode)))) | |
400 (cond ((and lazy-lock-mode (not font-lock-mode)) | |
401 ;; Turned on `lazy-lock-mode' rather than `font-lock-mode'. | |
402 (let ((font-lock-support-mode 'lazy-lock-mode)) | |
403 (font-lock-mode t))) | |
404 (lazy-lock-mode | |
405 ;; Turn ourselves on. | |
406 (lazy-lock-install)) | |
407 (t | |
408 ;; Turn ourselves off. | |
409 (lazy-lock-unstall)))) | |
410 | |
411 (defun lazy-lock-submit-bug-report () | |
412 "Submit via mail a bug report on lazy-lock.el." | |
413 (interactive) | |
414 (let ((reporter-prompt-for-summary-p t)) | |
415 (reporter-submit-bug-report "simon@gnu.ai.mit.edu" "lazy-lock 2.05" | |
416 '(lazy-lock-minimum-size lazy-lock-defer-driven lazy-lock-defer-time | |
417 lazy-lock-stealth-time lazy-lock-stealth-nice lazy-lock-stealth-lines | |
418 lazy-lock-stealth-verbose) | |
419 nil nil | |
420 (concat "Hi Si., | |
421 | |
422 I want to report a bug. I've read the `Bugs' section of `Info' on Emacs, so I | |
423 know how to make a clear and unambiguous report. To reproduce the bug: | |
424 | |
425 Start a fresh Emacs via `" invocation-name " -no-init-file -no-site-file'. | |
426 In the `*scratch*' buffer, evaluate:")))) | |
427 | |
428 ;;;###autoload | |
429 (defun turn-on-lazy-lock () | |
430 "Unconditionally turn on Lazy Lock mode." | |
431 (lazy-lock-mode t)) | |
432 | |
433 (defun lazy-lock-install () | |
434 (let ((min-size (font-lock-value-in-major-mode lazy-lock-minimum-size))) | |
435 ;; | |
436 ;; Tell Font Lock whether Lazy Lock will do fontification. | |
437 (make-local-variable 'font-lock-fontified) | |
438 (setq font-lock-fontified (and min-size (>= (buffer-size) min-size))) | |
439 ;; | |
440 ;; Add the text properties and fontify. | |
441 (if (not font-lock-fontified) | |
442 (lazy-lock-after-fontify-buffer) | |
443 ;; Make sure we fontify in any existing windows showing the buffer. | |
444 (let ((windows (get-buffer-window-list (current-buffer) 'nomini t))) | |
445 (lazy-lock-after-unfontify-buffer) | |
446 (while windows | |
447 (lazy-lock-fontify-conservatively (car windows)) | |
448 (setq windows (cdr windows))))) | |
449 ;; | |
450 ;; Add the fontification hooks. | |
451 (lazy-lock-install-hooks | |
452 (or (numberp lazy-lock-defer-time) | |
453 (if (eq (car (car lazy-lock-defer-time)) 'not) | |
454 (not (memq major-mode (cdr (car lazy-lock-defer-time)))) | |
455 (memq major-mode (car lazy-lock-defer-time)))) | |
456 font-lock-fontified | |
457 (eq lazy-lock-defer-driven t)) | |
458 ;; | |
459 ;; Add the fontification timers. | |
460 (lazy-lock-install-timers | |
461 (or (cdr-safe lazy-lock-defer-time) lazy-lock-defer-time) | |
462 lazy-lock-stealth-time))) | |
463 | |
464 (defun lazy-lock-install-hooks (deferring fontifying defer-driven) | |
465 ;; | |
466 ;; Add hook if lazy-lock.el is deferring or is fontifying on scrolling. | |
467 (when (or deferring fontifying) | |
468 (make-local-hook 'window-scroll-functions) | |
469 (add-hook 'window-scroll-functions (if (and deferring defer-driven) | |
470 'lazy-lock-defer-after-scroll | |
471 'lazy-lock-fontify-after-scroll) | |
472 nil t)) | |
473 ;; | |
474 ;; Add hook if lazy-lock.el is not deferring and is fontifying. | |
475 (when (and (not deferring) fontifying) | |
476 (make-local-hook 'before-change-functions) | |
477 (add-hook 'before-change-functions 'lazy-lock-arrange-before-change nil t)) | |
478 ;; | |
479 ;; Add hook if lazy-lock.el is deferring. | |
480 (when deferring | |
481 (remove-hook 'after-change-functions 'font-lock-after-change-function t) | |
482 (add-hook 'after-change-functions 'lazy-lock-defer-after-change nil t)) | |
483 ;; | |
484 ;; Add package-specific hooks. | |
485 (make-local-hook 'outline-view-change-hook) | |
486 (add-hook 'outline-view-change-hook 'lazy-lock-fontify-after-outline nil t)) | |
487 | |
488 (defun lazy-lock-install-timers (dtime stime) | |
489 ;; Schedule or re-schedule the deferral and stealth timers. | |
490 ;; The layout of `lazy-lock-timers' is: | |
491 ;; ((DEFER-TIME . DEFER-TIMER) (STEALTH-TIME . STEALTH-TIMER) | |
492 ;; If an idle timeout has changed, cancel the existing idle timer (if there | |
493 ;; is one) and schedule a new one (if the new idle timeout is non-nil). | |
494 (unless (eq dtime (car (car lazy-lock-timers))) | |
495 (let ((defer (car lazy-lock-timers))) | |
496 (when (cdr defer) | |
497 (cancel-timer (cdr defer))) | |
498 (setcar lazy-lock-timers (cons dtime (and dtime | |
499 (run-with-idle-timer dtime t 'lazy-lock-fontify-after-defer)))))) | |
500 (unless (eq stime (car (cdr lazy-lock-timers))) | |
501 (let ((stealth (cdr lazy-lock-timers))) | |
502 (when (cdr stealth) | |
503 (cancel-timer (cdr stealth))) | |
504 (setcdr lazy-lock-timers (cons stime (and stime | |
505 (run-with-idle-timer stime t 'lazy-lock-fontify-after-idle))))))) | |
506 | |
507 (defun lazy-lock-unstall () | |
508 ;; | |
509 ;; Remove the text properties. | |
510 (lazy-lock-after-unfontify-buffer) | |
511 ;; | |
512 ;; Remove the fontification hooks. | |
513 (remove-hook 'window-scroll-functions 'lazy-lock-fontify-after-scroll t) | |
514 (remove-hook 'window-scroll-functions 'lazy-lock-defer-after-scroll t) | |
515 (remove-hook 'before-change-functions 'lazy-lock-arrange-before-change t) | |
516 (remove-hook 'after-change-functions 'lazy-lock-defer-after-change t) | |
517 (remove-hook 'outline-view-change-hook 'lazy-lock-fontify-after-outline t) | |
518 ;; | |
519 ;; If Font Lock mode is still enabled, reinstall its hook. | |
520 (when font-lock-mode | |
521 (add-hook 'after-change-functions 'font-lock-after-change-function nil t))) | |
522 | |
523 ;; Hook functions. | |
524 | |
525 (defun lazy-lock-fontify-after-scroll (window window-start) | |
526 ;; Called from `window-scroll-functions'. | |
527 ;; Fontify WINDOW from WINDOW-START. We cannot use `window-end' so we work | |
528 ;; out what it would be via `vertical-motion'. | |
529 (save-excursion | |
530 (goto-char window-start) | |
531 (vertical-motion (window-height window) window) | |
532 (lazy-lock-fontify-region window-start (point))) | |
533 ;; A prior deletion that did not cause scrolling, followed by a scroll, would | |
534 ;; result in an unnecessary trigger after this if we did not cancel it now. | |
535 (set-window-redisplay-end-trigger window nil)) | |
536 | |
537 (defun lazy-lock-fontify-after-trigger (window trigger-point) | |
538 ;; Called from `redisplay-end-trigger-functions'. | |
539 ;; Fontify WINDOW from TRIGGER-POINT. We cannot use `window-end' so we work | |
540 ;; out what it would be via `vertical-motion'. | |
541 ;; We could probably just use `lazy-lock-fontify-after-scroll' without loss: | |
542 ;; (lazy-lock-fontify-after-scroll window (window-start window)) | |
543 (save-excursion | |
544 (goto-char (window-start window)) | |
545 (vertical-motion (window-height window) window) | |
546 (lazy-lock-fontify-region trigger-point (point)))) | |
547 | |
548 (defun lazy-lock-fontify-after-resize (frame) | |
549 ;; Called from `window-size-change-functions'. | |
550 ;; Fontify windows in FRAME. We cannot use `window-start' or `window-end' so | |
551 ;; we fontify conservatively. | |
552 (save-excursion | |
553 (save-selected-window | |
554 (select-frame frame) | |
555 (walk-windows (function (lambda (window) | |
556 (set-buffer (window-buffer window)) | |
557 (when lazy-lock-mode | |
558 (lazy-lock-fontify-conservatively window)) | |
559 (set-window-redisplay-end-trigger window nil))) | |
560 'nomini frame)))) | |
561 | |
562 (defun lazy-lock-arrange-before-change (beg end) | |
563 ;; Called from `before-change-functions'. | |
564 ;; Arrange that if text becomes visible it will be fontified (if a deletion | |
565 ;; is pending, text might become visible at the bottom). | |
566 (unless (eq beg end) | |
567 (let ((windows (get-buffer-window-list (current-buffer) 'nomini t)) window) | |
568 (while windows | |
569 (setq window (car windows)) | |
570 (unless (markerp (window-redisplay-end-trigger window)) | |
571 (set-window-redisplay-end-trigger window (make-marker))) | |
572 (set-marker (window-redisplay-end-trigger window) (window-end window)) | |
573 (setq windows (cdr windows)))))) | |
574 | |
575 (defun lazy-lock-defer-after-scroll (window window-start) | |
576 ;; Called from `window-scroll-functions'. | |
577 ;; Defer fontification following the scroll. Save the current buffer so that | |
578 ;; we subsequently fontify in all windows showing the buffer. | |
579 (unless (memq (current-buffer) lazy-lock-buffers) | |
580 (push (current-buffer) lazy-lock-buffers))) | |
581 | |
582 (defun lazy-lock-defer-after-change (beg end old-len) | |
583 ;; Called from `after-change-functions'. | |
584 ;; Defer fontification of the current line. Save the current buffer so that | |
585 ;; we subsequently fontify in all windows showing the buffer. | |
586 (save-buffer-state nil | |
587 (unless (memq (current-buffer) lazy-lock-buffers) | |
588 (push (current-buffer) lazy-lock-buffers)) | |
589 (remove-text-properties | |
590 (max (1- beg) (point-min)) (min (1+ end) (point-max)) '(lazy-lock nil)))) | |
591 | |
592 (defun lazy-lock-fontify-after-defer () | |
593 ;; Called from `timer-idle-list'. | |
594 ;; Fontify all windows where deferral has occurred for its buffer. | |
595 (while (and lazy-lock-buffers (not (input-pending-p))) | |
596 (let ((windows (get-buffer-window-list (car lazy-lock-buffers) 'nomini t))) | |
597 (while windows | |
598 (lazy-lock-fontify-window (car windows)) | |
599 (setq windows (cdr windows))) | |
600 (setq lazy-lock-buffers (cdr lazy-lock-buffers)))) | |
601 ;; Add hook if fontification should be defer-driven from now on. | |
602 (unless (or (not lazy-lock-defer-driven) (eq lazy-lock-defer-driven t) | |
603 (memq 'lazy-lock-defer-after-scroll window-scroll-functions) | |
604 (input-pending-p) (lazy-lock-unfontified-p)) | |
605 (remove-hook 'window-scroll-functions 'lazy-lock-fontify-after-scroll t) | |
606 (add-hook 'window-scroll-functions 'lazy-lock-defer-after-scroll nil t))) | |
607 | |
608 (defun lazy-lock-fontify-after-idle () | |
609 ;; Called from `timer-idle-list'. | |
610 ;; Fontify all buffers that need it, stealthily while idle. | |
611 (unless (or executing-kbd-macro (window-minibuffer-p (selected-window))) | |
612 ;; Loop over all buffers, fontify stealthily for each if necessary. | |
613 (let ((buffers (buffer-list)) (continue t) message message-log-max) | |
614 (save-excursion | |
615 (do-while (and buffers continue) | |
616 (set-buffer (car buffers)) | |
617 (if (not (and lazy-lock-mode (lazy-lock-unfontified-p))) | |
618 (setq continue (not (input-pending-p))) | |
619 ;; Fontify regions in this buffer while there is no input. | |
620 (do-while (and (lazy-lock-unfontified-p) | |
621 (setq continue (sit-for lazy-lock-stealth-nice))) | |
622 (when lazy-lock-stealth-verbose | |
623 (if message | |
624 (message "Fontifying stealthily... %2d%% of %s" | |
625 (lazy-lock-percent-fontified) (buffer-name)) | |
626 (message "Fontifying stealthily...") | |
627 (setq message t))) | |
628 (lazy-lock-fontify-chunk))) | |
629 (setq buffers (cdr buffers)))) | |
630 (when message | |
631 (message "Fontifying stealthily...%s" (if continue "done" "quit"))) | |
632 ))) | |
633 | |
634 (defun lazy-lock-fontify-after-outline () | |
635 ;; Called from `outline-view-change-hook'. | |
636 ;; Fontify windows showing the current buffer, as its visibility has changed. | |
637 ;; This is a conspiracy hack between lazy-lock.el and noutline.el. | |
638 (let ((windows (get-buffer-window-list (current-buffer) 'nomini t))) | |
639 (while windows | |
640 (lazy-lock-fontify-conservatively (car windows)) | |
641 (setq windows (cdr windows))))) | |
642 | |
643 (defun lazy-lock-after-fontify-buffer () | |
644 ;; Called from `font-lock-after-fontify-buffer'. | |
645 ;; Mark the current buffer as fontified. | |
646 ;; This is a conspiracy hack between lazy-lock.el and font-lock.el. | |
647 (save-buffer-state nil | |
648 (add-text-properties (point-min) (point-max) '(lazy-lock t)))) | |
649 | |
650 (defun lazy-lock-after-unfontify-buffer () | |
651 ;; Called from `font-lock-after-unfontify-buffer'. | |
652 ;; Mark the current buffer as unfontified. | |
653 ;; This is a conspiracy hack between lazy-lock.el and font-lock.el. | |
654 (save-buffer-state nil | |
655 (remove-text-properties (point-min) (point-max) '(lazy-lock nil)))) | |
656 | |
657 ;; Fontification functions. | |
658 | |
659 ;; If packages want to ensure that some region of the buffer is fontified, they | |
660 ;; should use this function. For an example, see ps-print.el. | |
661 (defun lazy-lock-fontify-region (beg end) | |
662 ;; Fontify between BEG and END, where necessary, in the current buffer. | |
663 (when (setq beg (text-property-any beg end 'lazy-lock nil)) | |
664 (save-excursion | |
665 (save-match-data | |
666 (save-buffer-state | |
667 ;; Ensure syntactic fontification is always correct. | |
668 (font-lock-beginning-of-syntax-function next) | |
669 ;; Find successive unfontified regions between BEG and END. | |
670 (condition-case data | |
671 (do-while beg | |
672 (setq next (or (text-property-any beg end 'lazy-lock t) end)) | |
673 ;; Make sure the region end points are at beginning of line. | |
674 (goto-char beg) | |
675 (unless (bolp) | |
676 (beginning-of-line) | |
677 (setq beg (point))) | |
678 (goto-char next) | |
679 (unless (bolp) | |
680 (forward-line) | |
681 (setq next (point))) | |
682 ;; Fontify the region, then flag it as fontified. | |
683 (font-lock-fontify-region beg next) | |
684 (add-text-properties beg next '(lazy-lock t)) | |
685 (setq beg (text-property-any next end 'lazy-lock nil))) | |
686 ((error quit) (message "Fontifying region...%s" data)))))))) | |
687 | |
688 (defun lazy-lock-fontify-chunk () | |
689 ;; Fontify the nearest chunk, for stealth, in the current buffer. | |
690 (save-excursion | |
691 (save-restriction | |
692 (widen) | |
693 ;; Move to end of line in case the character at point is not fontified. | |
694 (end-of-line) | |
695 ;; Find where the previous, and next, unfontified regions end, and begin. | |
696 (let ((prev (previous-single-property-change (point) 'lazy-lock)) | |
697 (next (text-property-any (point) (point-max) 'lazy-lock nil))) | |
698 ;; Fontify from the nearest unfontified position. | |
699 (if (or (null prev) (and next (< (- next (point)) (- (point) prev)))) | |
700 ;; The next, or neither, region is the nearest not fontified. | |
701 (lazy-lock-fontify-region | |
702 (progn (goto-char (or next (point-min))) | |
703 (beginning-of-line) | |
704 (point)) | |
705 (progn (goto-char (or next (point-min))) | |
706 (forward-line lazy-lock-stealth-lines) | |
707 (point))) | |
708 ;; The previous region is the nearest not fontified. | |
709 (lazy-lock-fontify-region | |
710 (progn (goto-char prev) | |
711 (forward-line (- lazy-lock-stealth-lines)) | |
712 (point)) | |
713 (progn (goto-char prev) | |
714 (forward-line) | |
715 (point)))))))) | |
716 | |
717 (defun lazy-lock-fontify-window (window) | |
718 ;; Fontify in WINDOW between `window-start' and `window-end'. | |
719 ;; We can only do this when we can use `window-start' and `window-end'. | |
720 (save-excursion | |
721 (set-buffer (window-buffer window)) | |
722 (lazy-lock-fontify-region (window-start window) (window-end window)))) | |
723 | |
724 (defun lazy-lock-fontify-conservatively (window) | |
725 ;; Fontify in WINDOW conservatively around point. | |
726 ;; Where we cannot use `window-start' and `window-end' we do `window-height' | |
727 ;; lines around point. That way we guarantee to have done enough. | |
728 (save-excursion | |
729 (set-buffer (window-buffer window)) | |
730 (lazy-lock-fontify-region | |
731 (save-excursion | |
732 (vertical-motion (- (window-height window)) window) (point)) | |
733 (save-excursion | |
734 (vertical-motion (window-height window) window) (point))))) | |
735 | |
736 (defun lazy-lock-unfontified-p () | |
737 ;; Return non-nil if there is anywhere still to be fontified. | |
738 (save-restriction | |
739 (widen) | |
740 (text-property-any (point-min) (point-max) 'lazy-lock nil))) | |
741 | |
742 (defun lazy-lock-percent-fontified () | |
743 ;; Return the percentage (of characters) of the buffer that are fontified. | |
744 (save-restriction | |
745 (widen) | |
746 (let ((beg (point-min)) (end (point-max)) (size 0) next) | |
747 ;; Find where the next fontified region begins. | |
748 (while (setq beg (text-property-any beg end 'lazy-lock t)) | |
749 (setq next (or (text-property-any beg end 'lazy-lock nil) end) | |
750 size (+ size (- next beg)) | |
751 beg next)) | |
752 (/ (* size 100) (buffer-size))))) | |
753 | |
754 ;; Version dependent workarounds and fixes. | |
755 | |
756 (when (if (save-match-data (string-match "Lucid\\|XEmacs" (emacs-version))) | |
757 nil | |
758 (and (= emacs-major-version 19) (= emacs-minor-version 30))) | |
759 ;; | |
760 ;; We use `post-command-idle-hook' for deferral and stealth. Oh Lordy. | |
761 (defun lazy-lock-install-timers (foo bar) | |
762 (add-hook 'post-command-idle-hook 'lazy-lock-fontify-post-command t) | |
763 (add-hook 'post-command-idle-hook 'lazy-lock-fontify-post-idle t) | |
764 (add-to-list 'lazy-lock-install (current-buffer)) | |
765 (add-hook 'post-command-hook 'lazy-lock-fontify-after-install)) | |
766 (defun lazy-lock-fontify-post-command () | |
767 (and lazy-lock-buffers (not executing-kbd-macro) | |
768 (progn | |
769 (and deactivate-mark (deactivate-mark)) | |
770 (sit-for | |
771 (or (cdr-safe lazy-lock-defer-time) lazy-lock-defer-time 0))) | |
772 (lazy-lock-fontify-after-defer))) | |
773 (defun lazy-lock-fontify-post-idle () | |
774 (and lazy-lock-stealth-time (not executing-kbd-macro) | |
775 (not (window-minibuffer-p (selected-window))) | |
776 (progn | |
777 (and deactivate-mark (deactivate-mark)) | |
778 (sit-for lazy-lock-stealth-time)) | |
779 (lazy-lock-fontify-after-idle))) | |
780 ;; | |
781 ;; Simulate running of `window-scroll-functions' in `set-window-buffer'. | |
782 (defvar lazy-lock-install nil) | |
783 (defun lazy-lock-fontify-after-install () | |
784 (remove-hook 'post-command-hook 'lazy-lock-fontify-after-install) | |
785 (while lazy-lock-install | |
786 (mapcar 'lazy-lock-fontify-conservatively | |
787 (get-buffer-window-list (pop lazy-lock-install) 'nomini t))))) | |
788 | |
789 ;; Possibly absent. | |
790 | |
791 (unless (boundp 'font-lock-inhibit-thing-lock) | |
792 ;; Font Lock mode uses this to direct Lazy and Fast Lock modes to stay off. | |
793 (defvar font-lock-inhibit-thing-lock nil | |
794 "List of Font Lock mode related modes that should not be turned on.")) | |
795 | |
796 (unless (fboundp 'font-lock-value-in-major-mode) | |
797 (defun font-lock-value-in-major-mode (alist) | |
798 ;; Return value in ALIST for `major-mode'. | |
799 (if (consp alist) | |
800 (cdr (or (assq major-mode alist) (assq t alist))) | |
801 alist))) | |
802 | |
803 (unless (fboundp 'get-buffer-window-list) | |
804 ;; We use this to get all windows showing a buffer we have to fontify. | |
805 (defun get-buffer-window-list (buffer &optional minibuf frame) | |
806 "Return windows currently displaying BUFFER, or nil if none." | |
807 (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows) | |
808 (walk-windows (function (lambda (window) | |
809 (when (eq (window-buffer window) buffer) | |
810 (push window windows)))) | |
811 minibuf frame) | |
812 windows))) | |
813 | |
814 ;; Install ourselves: | |
815 | |
816 ;; We don't install ourselves on `font-lock-mode-hook' as other packages can be | |
817 ;; used with font-lock.el, and lazy-lock.el should be dumpable without forcing | |
818 ;; people to get lazy or making it difficult for people to use alternatives. | |
819 (add-hook 'window-size-change-functions 'lazy-lock-fontify-after-resize) | |
820 (add-hook 'redisplay-end-trigger-functions 'lazy-lock-fontify-after-trigger) | |
821 | |
822 (unless (assq 'lazy-lock-mode minor-mode-alist) | |
823 (setq minor-mode-alist (append minor-mode-alist '((lazy-lock-mode nil))))) | |
824 | |
825 ;; Provide ourselves: | |
826 | |
827 (provide 'lazy-lock) | |
828 | |
829 ;;; lazy-lock.el ends here |