comparison lisp/packages/lazy-lock.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; lazy-lock.el --- Lazy demand-driven fontification for fast Font Lock mode.
2
3 ;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4
5 ;; Author: Simon Marshall <simon@gnu.ai.mit.edu>
6 ;; Keywords: faces files
7 ;; Version: 1.14
8
9 ;; LCD Archive Entry:
10 ;; lazy-lock|Simon Marshall|simon@gnu.ai.mit.edu|
11 ;; Lazy Font Lock mode (with fast demand-driven fontification).|
12 ;; 13-Oct-95|1.14|~/modes/lazy-lock.el.Z|
13
14 ;; The archive is archive.cis.ohio-state.edu in /pub/gnu/emacs/elisp-archive.
15
16 ;;; This file is part of GNU Emacs.
17
18 ;; GNU Emacs is free software; you can redistribute it and/or modify
19 ;; it under the terms of the GNU General Public License as published by
20 ;; the Free Software Foundation; either version 2, or (at your option)
21 ;; any later version.
22
23 ;; GNU Emacs is distributed in the hope that it will be useful,
24 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 ;; GNU General Public License for more details.
27
28 ;; You should have received a copy of the GNU General Public License
29 ;; along with GNU Emacs; see the file COPYING. If not, write to
30 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31
32 ;;; Synched up with: Not in FSF. (This seems very strange to me.)
33
34 ;;; Commentary:
35
36 ;; Purpose:
37 ;;
38 ;; To make visiting buffers in `font-lock-mode' faster by making fontification
39 ;; be demand-driven and stealthy.
40 ;; Fontification only occurs when, and where, necessary.
41 ;;
42 ;; See caveats and feedback below. See also the defer-lock and fast-lock
43 ;; packages. (But don't use lazy-lock.el and fast-lock.el at the same time!)
44
45 ;; Installation:
46 ;;
47 ;; Put this file somewhere where Emacs can find it (i.e., in one of the paths
48 ;; in your `load-path'), `byte-compile-file' it, and put in your ~/.emacs:
49 ;;
50 ;; (autoload 'turn-on-lazy-lock "lazy-lock"
51 ;; "Unconditionally turn on Lazy Lock mode.")
52 ;;
53 ;; (add-hook 'font-lock-mode-hook 'turn-on-lazy-lock)
54 ;;
55 ;; Start up a new Emacs and use font-lock as usual (except that you can use the
56 ;; so-called "gaudier" fontification regexps on big files without frustration).
57 ;;
58 ;; In a buffer (which has `font-lock-mode' enabled) which is at least
59 ;; `lazy-lock-minimum-size' characters long, only the visible portion of the
60 ;; buffer will be fontified. Motion around the buffer will fontify those
61 ;; visible portions that were not previous fontified. If the variable
62 ;; `lazy-lock-hide-invisible' is non-nil, redisplay will be delayed until after
63 ;; fontification. Otherwise, text that has not yet been fontified is displayed
64 ;; in `lazy-lock-invisible-foreground'.
65 ;;
66 ;; If stealth fontification is enabled, fontification will occur in invisible
67 ;; parts of the buffer after `lazy-lock-stealth-time' seconds of idle time.
68
69 ;; Advanced Use:
70 ;;
71 ;; You can also do fancy things with `advice'. For example, to fontify when
72 ;; dragging the scroll-bar in Emacs, you could put in your ~/.emacs:
73 ;;
74 ;; (autoload 'lazy-lock-post-command-fontify-windows "lazy-lock")
75 ;;
76 ;; (defadvice scroll-bar-drag-1 (after fontify-window activate compile)
77 ;; (let ((lazy-lock-walk-windows nil) (lazy-lock-hide-invisible nil))
78 ;; (lazy-lock-post-command-fontify-windows)))
79 ;;
80 ;; Or to fontify when the Debugger pops up a source code window:
81 ;;
82 ;; (autoload 'lazy-lock-fontify-walk-windows "lazy-lock")
83 ;;
84 ;; (defadvice gud-display-line (after fontify-window activate compile)
85 ;; (let ((lazy-lock-walk-windows t) (lazy-lock-hide-invisible t))
86 ;; (lazy-lock-fontify-walk-windows)))
87 ;;
88 ;; Scott Byer <byer@mv.us.adobe.com> suggested this to fontify the visible part
89 ;; of an insertion only:
90 ;;
91 ;; (defvar lazy-lock-insert-commands
92 ;; '(yank yank-pop clipboard-yank hilit-yank hilit-yank-pop
93 ;; mail-yank-original mouse-yank-at-click mouse-yank-secondary
94 ;; yank-rectangle)
95 ;; "A list of insertion commands.")
96 ;;
97 ;; (defadvice font-lock-after-change-function (around fontify-insertion
98 ;; activate compile)
99 ;; (if (or (not (memq this-command lazy-lock-insert-commands))
100 ;; (and (pos-visible-in-window-p beg) (pos-visible-in-window-p end)))
101 ;; ad-do-it
102 ;; (let ((this-command 'ignore))
103 ;; (put-text-property beg end 'fontified nil)
104 ;; (lazy-lock-fontify-window))))
105 ;;
106 ;; Let me know if you use any other `advice' and I'll put it here. Thanks.
107 ;;
108 ;; These kinds of things with `advice' aren't done automatically because they
109 ;; cause large packages (advice.el plus bytecomp.el and friends) to be loaded.
110
111 ;; Caveats:
112 ;;
113 ;; Lazy Lock mode does not work efficiently with Outline mode. This is because
114 ;; when in Outline mode, although text may be hidden (not visible in the
115 ;; window), the text is visible to Emacs Lisp code (not surprisingly) and Lazy
116 ;; Lock fontifies it mercilessly. Hopefully this will be fixed one day.
117 ;;
118 ;; Lazy Lock mode does not fontify windows as they appear:
119 ;;
120 ;; 1. With `query-replace' or `ispell-*', as Lazy Lock only knows about point
121 ;; motion after the command exits.
122 ;;
123 ;; 2. When displayed by gud.el (the Grand Unified Debugger), as they are
124 ;; displayed via a process sentinel. See `Advanced Use' above.
125 ;;
126 ;; 3. In XEmacs 19.12, when the last command was invoked via a mouse event,
127 ;; because of a bug/feature in/of `sit-for'.
128 ;;
129 ;; 4. In other random situations that I don't know about (yet).
130 ;;
131 ;; If you have `lazy-lock-hide-invisible' you may notice that redisplay occurs
132 ;; before fontification regardlessly. This is due to other packages sitting on
133 ;; `post-command-hook' and provoking redisplay. If you use these packages, you
134 ;; can't use `lazy-lock-hide-invisible'.
135 ;;
136 ;; If you have `lazy-lock-hide-invisible' and use scrollbar scrolling using
137 ;; Emacs 19, hidden text will not be fontified as it becomes visible. It is
138 ;; expected that Emacs 19 will provide the necessary hooks in future, to solve
139 ;; this problem and the problem above.
140 ;;
141 ;; Unless otherwise stated, "Emacs 19.X" means versions up to and including X.
142 ;;
143 ;; In Emacs 19.25, one `window-start'/`window-end' bug means that if you open a
144 ;; file in another frame (such as via `find-tag-other-frame'), the whole buffer
145 ;; is fontified regardless. Upgrade!
146 ;;
147 ;; In Emacs 19.25, fontification by stealth is turned off because of a fatal
148 ;; bug in `previous-single-property-change'. Upgrade!
149 ;;
150 ;; In Emacs 19.28, if you see a message in the minibuffer of the form
151 ;; "Fontifying window... done. (Restarted in foo.c)"
152 ;; it means the Garbage Collector has marked some (subsequently used) text
153 ;; properties. Lazy Lock attempts to recover the situation by restarting in
154 ;; that buffer. Unfortunately, that buffer will be left in a writable and
155 ;; modified state. Also, other windows may not be fontified when this happens.
156 ;; To reduce the frequency of this bug occuring, increase in your ~/.emacs the
157 ;; value of `gc-cons-threshold' to, say, 1Meg, e.g.:
158 ;;
159 ;; (setq gc-cons-threshold (* 1024 1024))
160 ;;
161 ;; The solution is to upgrade! (With thanks to Kevin Broadey for help here.)
162 ;;
163 ;; For XEmacs 19.11 and Lucid Emacs 19.10 users, lazy-lock sort-of works.
164 ;; There are bugs in text property and point/window primatives. Upgrade!
165
166 ;; Feedback:
167 ;;
168 ;; Feedback is welcome.
169 ;; To submit a bug report (or make comments) please use the mechanism provided:
170 ;;
171 ;; M-x lazy-lock-submit-bug-report RET
172
173 ;; History:
174 ;;
175 ;; 0.01--1.00:
176 ;; - Changed name from fore-lock to lazy-lock. Shame though.
177 ;; - Dropped `advice'-wrapping completely. Ask me if you're interested in it.
178 ;; - Made `lazy-lock-mode' ignore `post-command-hook' and `buffer-file-name'.
179 ;; - Made `lazy-lock-fontify-window' check `lazy-lock-mode' and `this-command'.
180 ;; - Made `lazy-lock-fontify-window' redisplay via `sit-for'.
181 ;; - Added `lazy-lock-minimum-size' to control `lazy-lock-mode'.
182 ;; 1.00--1.01:
183 ;; - Added `lazy-lock-fontify-buffer'.
184 ;; - Made `lazy-lock-fontify-window' ignore `lazy-lock-mode'.
185 ;; - Made `lazy-lock-fontify-window' suspicious of `window-' favourites again.
186 ;; - Added `lazy-lock-delay-commands' (idea from William G. Dubuque).
187 ;; - Added `lazy-lock-ignore-commands' for completeness.
188 ;; - Added `lazy-lock-continuity-time' for normal input delay.
189 ;; 1.01--1.02:
190 ;; - Made `lazy-lock-fontify-window' cope with multiple unfontified regions.
191 ;; - Made `lazy-lock-mode' remove `fontified' properties if turned off.
192 ;; - Made `lazy-lock-fontify-window' fontify by lines.
193 ;; - Added `lazy-lock-cache-position' buffer local to detect visibility change.
194 ;; - Added `lazy-lock-post-command-hook' to do the waiting.
195 ;; - Made `lazy-lock-fontify-window' just do the fontification.
196 ;; - Made `lazy-lock-mode' append `lazy-lock-post-command-hook'.
197 ;; - Added `lazy-lock-walk-windows' to hack multi-window motion.
198 ;; - Made `lazy-lock-post-command-hook' `walk-windows' if variable is non-nil.
199 ;; - Removed `lazy-lock-ignore-commands' since insertion may change window.
200 ;; - Added `lazy-lock-fontify-stealthily' and `lazy-lock-stealth-time'.
201 ;; - Made `lazy-lock-post-command-hook' use them.
202 ;; 1.02--1.03:
203 ;; - Made `lazy-lock-fontify-stealthily' do `forward-line' not `previous-line'.
204 ;; - Made `lazy-lock-fontify-stealthily' `move-to-window-line' first.
205 ;; - Made `lazy-lock-fontify-stealthily' use `text-property-any' for region.
206 ;; - Made `lazy-lock-post-command-hook' loop on `lazy-lock-fontify-stealthily'.
207 ;; 1.03--1.04:
208 ;; - Made `lazy-lock-mode' reset `lazy-lock-cache-position'.
209 ;; - Made `lazy-lock-post-command-hook' `widen' for `if' `text-property-any'.
210 ;; - Made `lazy-lock-fontify-stealthily' return `text-property-any'.
211 ;; - Added `lazy-lock-percent-fontified' for a/be-musement.
212 ;; - Made `lazy-lock-post-command-hook' use it.
213 ;; - Made `lazy-lock-mode' use `make-local-hook' etc. if available.
214 ;; - Made `lazy-lock-mode' use `before-revert-hook' and `after-revert-hook'.
215 ;; - Made `lazy-lock-post-command-hook' protect `deactivate-mark'.
216 ;; - Adds `lazy-lock-post-command-hook' globally to `post-command-hook'.
217 ;; 1.04--1.05:
218 ;; - Made `lazy-lock-mode' test `make-local-hook' not `emacs-minor-version'.
219 ;; 1.05--1.06:
220 ;; - Added `lazy-lock-ignore-commands' for commands that leave no event but do.
221 ;; - Made `lazy-lock-post-command-hook' check `lazy-lock-ignore-commands'.
222 ;; 1.06--1.07:
223 ;; - Removed `before-revert-hook' and `after-revert-hook' use.
224 ;; 1.07--1.08:
225 ;; - Added `lazy-lock-submit-bug-report'.
226 ;; - Made `lazy-lock-post-command-hook' check `executing-macro'.
227 ;; - Made it sort-of/almost work for XEmacs (help from Jonas Jarnestrom).
228 ;; - XEmacs: Fix `text-property-not-all' (fix based on fast-lock.el 3.05 fix).
229 ;; - XEmacs: Set `font-lock-no-comments' and alias `frame-parameters'.
230 ;; - Made `byte-compile-warnings' omit `unresolved' on compilation.
231 ;; - Made `lazy-lock-post-command-hook' protect `buffer-undo-list'.
232 ;; - Moved `deactivate-mark' and `buffer-undo-list' protection to functions.
233 ;; - Added `lazy-lock-invisible-foreground' (idea from Boris Goldowsky).
234 ;; - XEmacs: Fix to use `text-property-not-all' t, not `text-property-any' nil.
235 ;; - Made `lazy-lock-percent-fontified' return `round' to an integer.
236 ;; - XEmacs: Fix `text-property-any' (fix and work around for a bug elsewhere).
237 ;; - XEmacs: Fix `lazy-lock-submit-bug-report' for reporter.el & vm-window.el.
238 ;; - XEmacs: Made `lazy-lock-fontify-window' loop `while' `<' not `/='.
239 ;; - Use `font-lock-after-change-function' to do the fontification.
240 ;; 1.08--1.09:
241 ;; - Made `lazy-lock-post-command-hook' protect with `condition-case'.
242 ;; - Made `lazy-lock-cache-start' to cache `window-start'.
243 ;; - Made `lazy-lock-fontify-window' check and cache `lazy-lock-cache-start'.
244 ;; - Renamed `lazy-lock-cache-position' to `lazy-lock-cache-end'.
245 ;; - XEmacs: Fix for `font-lock-after-change-function'.
246 ;; - Adds `lazy-lock-post-command-hook' globally to `window-setup-hook'.
247 ;; 1.09--1.10:
248 ;; - Made `buffer-file-name' be `let' to prevent supersession (Kevin Broadey).
249 ;; - Made `lazy-lock-submit-bug-report' `require' reporter (Ilya Zakharevich).
250 ;; - Made `lazy-lock-mode' and `turn-on-lazy-lock' succeed `autoload' cookies.
251 ;; - Added `lazy-lock-fontify-walk-windows' for walking window fontification.
252 ;; - Added `lazy-lock-fontify-walk-stealthily' for walking stealth.
253 ;; - Removed `move-to-window-line' from `lazy-lock-fontify-stealthily'.
254 ;; - Made `lazy-lock-percent-fontified' use `truncate' rather than `round'.
255 ;; - Added other `*-argument' to `lazy-lock-ignore-commands' (Kevin Broadey).
256 ;; - Made `lazy-lock-fontify-stealthily' not assume buffer is part `fontified'.
257 ;; - Emacs: Fix for `font-lock-fontify-region'.
258 ;; - Made `lazy-lock-post-command-hook' check for minibuffer (Kevin Broadey).
259 ;; - Added `lazy-lock-stealth-nice' for niceness during stealth fontification.
260 ;; - Added `lazy-lock-stealth-lines' for chunks of stealth fontification.
261 ;; 1.10--1.11: incorporated hack by Ben Wing from William Dubuque's fontifly.el
262 ;; - Made `lazy-lock-fontify-stealthily' see a non `fontified' preceding line.
263 ;; - XEmacs: Fix `text-property-any' and `text-property-not-all' (Ben Wing).
264 ;; - XEmacs: Fix `lazy-lock-continuity-time' (Ben Wing).
265 ;; - Added awful `lazy-lock-running-xemacs-p' (Ben Wing).
266 ;; - Made loading set `emacs-minor-version' if it's not bound.
267 ;; - Added `lazy-lock-hide-invisible' to control redisplay.
268 ;; - Made `lazy-lock-post-command-hook' use it in `sit-for' (Ben Wing).
269 ;; - Made `lazy-lock-fontify-window' move relative to `end-of-line' if non-nil.
270 ;; - Added `lazy-lock-fontify-region' so packages can ensure fontification.
271 ;; - Made `lazy-lock-fontify-walk-stealthily' do stealth widening.
272 ;; - Made `lazy-lock-fontify-stealthily' always do adjacent preceding regions.
273 ;; - Added `lazy-lock-after-fontify-buffer'.
274 ;; - XEmacs: Removed `font-lock-no-comments' incompatibility code.
275 ;; - Removed `lazy-lock-delay-time' and `lazy-lock-delay-commands'.
276 ;; - Removed `lazy-lock-post-command' and split the functionality.
277 ;; - Adds `lazy-lock-post-command-fontify-windows' on first.
278 ;; - Adds `lazy-lock-post-command-fontify-stealthily' on last.
279 ;; - Made `lazy-lock-mode' ensure both first and last on `post-command-hook'.
280 ;; - Made `lazy-lock-mode' ensure `font-lock-mode' is on.
281 ;; - Wrap `lazy-lock-post-command-fontify-stealthily' for errors (David Karr).
282 ;; - Added `calcDigit-key' to `lazy-lock-ignore-commands' (Bob Glickstein).
283 ;; - Wrap `lazy-lock-running-xemacs-p' with `eval-and-compile' (Erik Naggum).
284 ;; - XEmacs: Fix use of `previous-single-property-change' (Jim Thompson).
285 ;; - XEmacs: Fix `next-single-property-change' fix for 19.11 (Jim Thompson).
286 ;; - Added `lazy-lock-post-resize-fontify-windows' to fontify on resizing.
287 ;; - Adds globally to `window-size-change-functions'.
288 ;; - Added `lazy-lock-post-setup-fontify-windows' to fontify after start up.
289 ;; - Adds globally to `window-setup-hook'.
290 ;; - Made `lazy-lock-post-command-fontify-windows' check for `input-pending-p'.
291 ;; - Made `save-selected-window' to restore the `selected-window'.
292 ;; - Use `save-selected-window' rather than `save-window-excursion'.
293 ;; 1.11--1.12:
294 ;; - Made `lazy-lock-post-command-fontify-windows' do `set-buffer' first.
295 ;; - Made `lazy-lock-fontify-stealthily' respect narrowing before point.
296 ;; - Added `lazy-lock-post-setup-ediff-control-frame' for Ediff control frame.
297 ;; - Adds globally to `ediff-after-setup-control-frame-hooks'.
298 ;; - Wrap `save-selected-window' with `save-excursion' for `current-buffer'.
299 ;; 1.12--1.13:
300 ;; - XEmacs: Add `lazy-lock-after-fontify-buffer' to the Font Lock hook.
301 ;; - Made `buffer-file-truename' also wrapped for supersession (Rick Sladkey).
302 ;; - Made `font-lock-beginning-of-syntax-function' wrapped for fontification.
303 ;; - Added `lazy-lock-stealth-verbose' (after harassment from Ben Wing).
304 ;; - XEmacs: Made `font-lock-verbose' wrapped for stealth fontification.
305 ;; 1.13--1.14:
306 ;; - Wrap `lazy-lock-colour-invisible' for `set-face-foreground' (Jari Aalto).
307
308 (require 'font-lock)
309
310 (eval-when-compile
311 ;; Only `require' so `ediff-multiframe-setup-p' is expanded at compile time.
312 (condition-case nil (require 'ediff) (file-error))
313 ;; Well, shouldn't Lazy Lock be as lazy as possible?
314 ;(setq byte-compile-dynamic t byte-compile-dynamic-docstrings t)
315 ;; Shut Emacs' byte-compiler up (cf. stop me getting mail from users).
316 (setq byte-compile-warnings '(free-vars callargs redefine)))
317
318 (defun lazy-lock-submit-bug-report ()
319 "Submit via mail a bug report on lazy-lock.el."
320 (interactive)
321 (require 'reporter)
322 (let ((reporter-prompt-for-summary-p t))
323 (reporter-submit-bug-report "simon@gnu.ai.mit.edu" "lazy-lock 1.14"
324 '(lazy-lock-walk-windows lazy-lock-continuity-time
325 lazy-lock-stealth-time lazy-lock-stealth-nice
326 lazy-lock-stealth-lines lazy-lock-stealth-verbose
327 lazy-lock-hide-invisible lazy-lock-invisible-foreground
328 lazy-lock-minimum-size lazy-lock-ignore-commands)
329 nil nil
330 (concat "Hi Si.,
331
332 I want to report a bug. I've read the `Bugs' section of `Info' on Emacs, so I
333 know how to make a clear and unambiguous report. To reproduce the bug:
334
335 Start a fresh Emacs via `" invocation-name " -no-init-file -no-site-file'.
336 In the `*scratch*' buffer, evaluate:"))))
337
338 ;; Let's define `emacs-major-version', `emacs-minor-version', and
339 ;; `emacs-version>=' if no-one else has.
340
341 (if (not (boundp 'emacs-major-version))
342 (eval-and-compile
343 (defconst emacs-major-version
344 (progn (or (string-match "^[0-9]+" emacs-version)
345 (error "emacs-version unparsable"))
346 (string-to-int (match-string 0 emacs-version)))
347 "Major version number of this version of Emacs, as an integer.
348 Warning, this variable did not exist in Emacs versions earlier than:
349 FSF Emacs: 19.23
350 XEmacs: 19.10")))
351
352 (if (not (boundp 'emacs-minor-version))
353 (eval-and-compile
354 (defconst emacs-minor-version
355 (progn (or (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version)
356 (error "emacs-version unparsable"))
357 (string-to-int (match-string 1 emacs-version)))
358 "Minor version number of this version of Emacs, as an integer.
359 Warning, this variable did not exist in Emacs versions earlier than:
360 FSF Emacs: 19.23
361 XEmacs: 19.10")))
362
363 (if (not (fboundp 'emacs-version>=))
364 (eval-and-compile
365 (defun emacs-version>= (major &optional minor)
366 "Return true if the Emacs version is >= to the given MAJOR and MINOR numbers.
367
368 The MAJOR version number argument is required, but the MINOR version number
369 argument is optional. If the minor version number is not specified (or is the
370 symbol `nil') then only the major version numbers are considered in the test."
371 (if (null minor)
372 (>= emacs-major-version major)
373 (or (> emacs-major-version major)
374 (and (= emacs-major-version major)
375 (>= emacs-minor-version minor))
376 )
377 ))))
378
379 ;; Yuck, but we make so much use of this variable it's probably worth it.
380 (eval-and-compile
381 (defconst lazy-lock-running-xemacs-p
382 (not (null (save-match-data (string-match "Lucid" emacs-version))))))
383
384 (defvar lazy-lock-cache-start nil) ; for window fontifiction
385 (defvar lazy-lock-cache-end nil) ; for window fontifiction
386 (defvar lazy-lock-cache-continue nil) ; for stealth fontifiction
387
388 ;;;###autoload
389 (defvar lazy-lock-mode nil) ; for modeline
390
391 ;; User Variables:
392
393 (defvar lazy-lock-minimum-size (* 25 1024)
394 "*If non-nil, the minimum size for buffers.
395 Only buffers more than this can have demand-driven fontification.
396 If nil, means size is irrelevant.")
397
398 (defvar lazy-lock-walk-windows t
399 "*If non-nil, fontify windows other than the selected window.
400 If `all-frames', fontify windows even on other frames.
401 A non-nil value slows down redisplay.")
402
403 ;; XEmacs 19.11 and below exercise a bug in the Xt event loop.
404 (defvar lazy-lock-continuity-time
405 (if (or (not lazy-lock-running-xemacs-p) (emacs-version>= 19 12))
406 0
407 (if (featurep 'lisp-float-type) 0.001 1))
408 "*Time in seconds to delay before normal window fontification.
409 Window fontification occurs if there is no input within this time.")
410
411 ;; `previous-single-property-change' at `point-min' up to Emacs 19.25 is fatal.
412 ;; `text-property-any', `text-property-not-all' and
413 ;; `next-single-property-change' up to XEmacs 19.11 are too broke.
414 (defvar lazy-lock-stealth-time
415 (if (emacs-version>= 19 (if lazy-lock-running-xemacs-p 12 26)) 30)
416 "*Time in seconds to delay before beginning stealth fontification.
417 Stealth fontification occurs if there is no input within this time.
418 If nil, means no fontification by stealth.")
419
420 (defvar lazy-lock-stealth-lines
421 (cond ((boundp 'font-lock-maximum-decoration)
422 (if font-lock-maximum-decoration 75 150))
423 ((boundp 'font-lock-use-maximal-decoration)
424 (if font-lock-use-maximal-decoration 50 100))
425 (t
426 50))
427 "*If non-nil, the maximum size of a chunk of stealth fontification.
428 Each iteration of stealth fontification can fontify this number of lines.
429 To speed up input response during stealth fontification, at the cost of stealth
430 taking longer to fontify, you could reduce the value of this variable.
431 If nil, means use `window-height' for the maximum chunk size.")
432
433 (defvar lazy-lock-stealth-nice (if (featurep 'lisp-float-type) 0.125 1)
434 "*Time in seconds to pause during chunks of stealth fontification.
435 To reduce machine load during stealth fontification, at the cost of stealth
436 taking longer to fontify, you could increase the value of this variable.")
437
438 (defvar lazy-lock-stealth-verbose font-lock-verbose
439 "*If non-nil, means stealth fontification should show status messages.")
440
441 (defvar lazy-lock-ignore-commands
442 (append
443 ;; Standard commands...
444 '(universal-argument digit-argument negative-argument
445 isearch-other-control-char isearch-other-meta-char)
446 ;; And some resulting from non-standard packages...
447 (if (fboundp 'calc) '(calcDigit-key)))
448 "A list of commands after which fontification should not occur.
449 To speed up typing response, at the cost of Lazy Lock not fontifying when
450 insertion causes scrolling, you could add `self-insert-command' to this list.")
451
452 (defvar lazy-lock-hide-invisible lazy-lock-running-xemacs-p
453 "*If non-nil, hide invisible text while it is fontified.
454 If non-nil, redisplay is delayed until after fontification occurs. If nil,
455 text is shown (in `lazy-lock-invisible-foreground') while it is fontified.
456 A non-nil value slows down redisplay and can slow down cursor motion.")
457
458 (defvar lazy-lock-invisible-foreground "gray50"
459 "The foreground colour to use to display invisible text.
460 If nil, the default foreground is used. If t, the default background is used.
461 If a string, it should be a colour to use (either its name or its RGB value).
462 Invisible text is momentarily seen (if `lazy-lock-hide-invisible' is nil) when
463 scrolling into unfontified regions.")
464
465 ;; User Functions:
466
467 ;;;###autoload
468 (defun lazy-lock-mode (&optional arg)
469 "Toggle Lazy Lock mode.
470 With arg, turn Lazy Lock mode on if and only if arg is positive and the buffer
471 is at least `lazy-lock-minimum-size' characters long.
472
473 When Lazy Lock mode is enabled, fontification is demand-driven and stealthy:
474
475 - Fontification occurs in visible parts of buffers when necessary.
476 Occurs if there is no input after pausing for `lazy-lock-continuity-time'.
477
478 - Fontification occurs in invisible parts when Emacs has been idle.
479 Occurs if there is no input after pausing for `lazy-lock-stealth-time'.
480
481 If `lazy-lock-hide-invisible' is non-nil, text is not displayed until it is
482 fontified, otherwise it is displayed in `lazy-lock-invisible-foreground'.
483
484 See also variables `lazy-lock-walk-windows' and `lazy-lock-ignore-commands' for
485 window (scroll) fontification, and `lazy-lock-stealth-lines',
486 `lazy-lock-stealth-nice' and `lazy-lock-stealth-verbose' for stealth
487 fontification.
488
489 Use \\[lazy-lock-submit-bug-report] to send bug reports or feedback."
490 (interactive "P")
491 (set (make-local-variable 'lazy-lock-mode)
492 (and (<= (or lazy-lock-minimum-size 0) (buffer-size))
493 (if arg (> (prefix-numeric-value arg) 0) (not lazy-lock-mode))))
494 (if (and lazy-lock-mode (not font-lock-mode))
495 ;; Turned on `lazy-lock-mode' rather than using `font-lock-mode-hook'.
496 (progn
497 (add-hook 'font-lock-mode-hook 'turn-on-lazy-lock)
498 (font-lock-mode 1))
499 (lazy-lock-fixup-hooks)
500 ;; Let's get down to business.
501 (if (not lazy-lock-mode)
502 (let ((modified (buffer-modified-p)) (inhibit-read-only t)
503 (buffer-undo-list t)
504 deactivate-mark buffer-file-name buffer-file-truename)
505 (remove-text-properties (point-min) (point-max) '(fontified nil))
506 (or modified (set-buffer-modified-p nil)))
507 (if (and (not lazy-lock-hide-invisible) lazy-lock-invisible-foreground)
508 (lazy-lock-colour-invisible))
509 (set (make-local-variable 'lazy-lock-cache-start) 0)
510 (set (make-local-variable 'lazy-lock-cache-end) 0)
511 (set (make-local-variable 'font-lock-fontified) t))))
512
513 ;;;###autoload
514 (defun turn-on-lazy-lock ()
515 "Unconditionally turn on Lazy Lock mode."
516 (lazy-lock-mode 1))
517
518 (if (not (emacs-version>= 19 (if lazy-lock-running-xemacs-p 12 29)))
519 ;; We don't need this in Emacs 19.29 or XEmacs 19.12.
520 (defun lazy-lock-fontify-buffer ()
521 "Fontify the current buffer where necessary."
522 (interactive)
523 (lazy-lock-fontify-region (point-min) (point-max))))
524
525 ;; API Functions:
526
527 (defun lazy-lock-fixup-hooks ()
528 ;; Make sure our hooks are correct.
529 (remove-hook 'pre-idle-hook 'lazy-lock-pre-idle-fontify-windows)
530 (remove-hook 'post-command-hook 'lazy-lock-post-command-fontify-stealthily)
531 ;; Make sure our hooks are at the end. Font-lock in XEmacs installs
532 ;; its own pre-idle-hook to implement deferral (#### something that
533 ;; should really be merged with this file; or more likely, lazy-lock
534 ;; in its entirety should be merged into font-lock).
535 (add-hook 'pre-idle-hook 'lazy-lock-pre-idle-fontify-windows t)
536 (add-hook 'post-command-hook 'lazy-lock-post-command-fontify-stealthily t)
537 ;; Fascistically remove font-lock's after-change-function and install
538 ;; our own. We know better than font-lock what to do. Otherwise,
539 ;; revert-buffer, insert-file, etc. cause full refontification of the
540 ;; entire changed area.
541 (if lazy-lock-mode
542 (progn
543 (remove-hook 'after-change-functions 'font-lock-after-change-function
544 t)
545 (make-local-hook 'after-change-functions)
546 (add-hook 'after-change-functions 'lazy-lock-after-change-function
547 nil t))
548 (remove-hook 'after-change-functions 'lazy-lock-after-change-function t)
549 (if font-lock-mode
550 (add-hook 'after-change-functions 'font-lock-after-change-function
551 nil t)))
552 )
553
554 ;; use put-nonduplicable-text-property to avoid unfriendly behavior
555 ;; when doing undo, etc. We really don't want syntax-highlighting text
556 ;; properties copied into strings or tracked by undo.
557 ;;
558 ;; #### If start-open and end-open really behaved like they are supposed to,
559 ;; we wouldn't really need this. I kind of fixed them up, but there's still
560 ;; a bug -- inserting text into the middle of a region of
561 ;; (start-open t end-open t) text should cause it not to inherit, but it
562 ;; does.
563
564 (if lazy-lock-running-xemacs-p
565 (defalias 'lazy-lock-put-text-property 'put-nonduplicable-text-property)
566 (defalias 'lazy-lock-put-text-property 'put-text-property))
567
568 (defun lazy-lock-fontify-region (start end &optional buffer)
569 "Fontify between START and END in BUFFER where necessary."
570 (save-excursion
571 (and buffer (set-buffer buffer))
572 (save-restriction
573 (narrow-to-region start end)
574 (let ((lazy-lock-stealth-lines (count-lines start end)))
575 (while (text-property-not-all start end 'fontified t)
576 (lazy-lock-fontify-stealthily))))))
577
578 (defun lazy-lock-after-fontify-buffer ()
579 ;; Mark the buffer as `fontified'.
580 (let ((modified (buffer-modified-p)) (inhibit-read-only t)
581 (buffer-undo-list t)
582 deactivate-mark buffer-file-name buffer-file-truename)
583 (lazy-lock-put-text-property (point-min) (point-max) 'fontified t)
584 (or modified (set-buffer-modified-p nil))))
585
586 ;; Just a cleaner-looking way of coping with Emacs' and XEmacs' `sit-for'.
587 (defmacro lazy-lock-sit-for (seconds &optional nodisp)
588 (if lazy-lock-running-xemacs-p
589 (` (sit-for (, seconds) (, nodisp)))
590 (` (sit-for (, seconds) 0 (, nodisp)))))
591
592 ;; Using `save-window-excursion' provokes `window-size-change-functions'.
593 ;; I prefer `save-walking-excursion', of course, because I have a warped mind.
594 (if (fboundp 'save-selected-window)
595 nil
596 (eval-and-compile
597 (defmacro save-selected-window (&rest body)
598 "Execute the BODY forms, restoring the selected window.
599 Does not restore the value of point in the selected window, or anything else."
600 (` (let ((original-window (selected-window)))
601 (unwind-protect
602 (progn (,@ body))
603 (select-window original-window))))))
604 (put 'save-selected-window 'lisp-indent-function 0))
605
606 ;; Functions for hooks:
607
608 ;; lazy-lock optimization:
609 ;;
610 ;; pre-idle-hook is called an awful lot -- pretty much every time the
611 ;; mouse moves or a timeout expires, for example. On Linux (sometimes),
612 ;; IRIX 5.x, and Solaris 2.something, it happens every 1/4 of a second
613 ;; due to the 1/4-second timers installed to compensate for various
614 ;; operating system deficiencies in the handling of SIGIO and SIGCHLD.
615 ;; (Those timers cause a cycle of the event loop. They don't necessarily
616 ;; have to, but rewriting to avoid this is fairly tricky and requires
617 ;; having significant amounts of code called from signal handlers, which
618 ;; (despite that fact that FSF Emacs reads its X input during a signal
619 ;; handler ?!), is almost always a bad idea -- it's extremely easy to
620 ;; introduce race conditions, which are very hard to track down.
621 ;;
622 ;; So to improve things, I added `frame-modified-tick'. This is an
623 ;; internal counter that gets ticked any time that any internal
624 ;; redisplay variable gets ticked. If `frame-modified-tick' is
625 ;; the same as the last time we checked, it means that redisplay will
626 ;; do absolutely nothing when encountering this frame, and thus we
627 ;; can skip out immediately. This happens when the 1/4-second timer
628 ;; fires while we're idle, or if we just move the mouse. (Moving
629 ;; around in a buffer changes `frame-modified-tick' because the
630 ;; internal redisplay variable "point_changed" gets ticked. We could
631 ;; easily improve things further by adding more tick counters, mirroring
632 ;; more closely the internal redisplay counters -- e.g. if we had
633 ;; another counter that didn't get ticked when point moved, we could
634 ;; tell if anything was going to happen by seeing if point is within
635 ;; window-start and window-end, since we know that redisplay will
636 ;; only do a window-scroll if it's not. (If window-start or window-end
637 ;; or window-buffer or anything else changed, windows_changed or
638 ;; some other variable will get ticked.))
639 ;;
640 ;; Also, it's wise to try and avoid things that cons. Avoiding
641 ;; `save-window-excursion', as we do, is definitely a major win
642 ;; because that's a heavy-duty function as regards consing and such.
643
644 (defvar lazy-lock-pre-idle-frame-modified-tick nil)
645 (defvar lazy-lock-pre-idle-selected-frame nil)
646
647 (defun lazy-lock-pre-idle-fontify-windows ()
648 ;; Do groovy things always unless we're in one of the ignored commands.
649 ;; The old version did the following five checks:
650 ;;
651 ;; (a) not in a macro,
652 ;; (b) no input pending,
653 ;; (c) got a real command (i.e. not an ignored command)
654 ;; (d) not in the minibuffer
655 ;; (e) no input after waiting for `lazy-lock-continuity-time'.
656 ;;
657 ;; (a), (b), and (e) are automatically taken care of by `pre-idle-hook'.
658 ;; I removed (d) because there doesn't seem to be any reason for it.
659 ;;
660 ;; Also, we do not have to `set-buffer' and in fact it would be
661 ;; incorrect to do so, since we may be being called from
662 ;; `accept-process-output' or whatever.
663 ;;
664 (if (memq this-command lazy-lock-ignore-commands)
665 (setq lazy-lock-cache-continue nil)
666 (setq lazy-lock-cache-continue t)
667 ;; #### we don't yet handle frame-modified-tick on multiple frames.
668 ;; handling this shouldn't be hard but I just haven't done it yet.
669 (if (or (eq 'all-frames lazy-lock-walk-windows)
670 (not (eq lazy-lock-pre-idle-selected-frame (selected-frame)))
671 (not (eq lazy-lock-pre-idle-frame-modified-tick
672 (frame-modified-tick (selected-frame)))))
673 (progn
674 ;; Do the visible parts of the buffer(s), i.e., the window(s).
675 (if (or (not lazy-lock-walk-windows)
676 (and (eq lazy-lock-walk-windows t) (one-window-p t)))
677 (if lazy-lock-mode (condition-case nil
678 (lazy-lock-fontify-window)))
679 (lazy-lock-fontify-walk-windows))
680 (setq lazy-lock-pre-idle-selected-frame (selected-frame))
681 (setq lazy-lock-pre-idle-frame-modified-tick
682 (frame-modified-tick (selected-frame)))))))
683
684 (defun lazy-lock-after-change-function (beg end old-len)
685 (and lazy-lock-mode
686 (if (= beg end)
687 (font-lock-after-change-function beg end old-len)
688 (lazy-lock-put-text-property beg end 'fontified nil))))
689
690 ;; DO NOT put this as a pre-idle hook! The sit-for messes up
691 ;; mouse dragging.
692 (defun lazy-lock-post-command-fontify-stealthily ()
693 ;; Do groovy things if (a-d) above, (e) not moving the mouse, and (f) no
694 ;; input after after waiting for `lazy-lock-stealth-time'.
695 (if (and lazy-lock-cache-continue lazy-lock-stealth-time)
696 (condition-case data
697 (if (lazy-lock-sit-for lazy-lock-stealth-time)
698 ;; Do the invisible parts of buffers.
699 (lazy-lock-fontify-walk-stealthily))
700 (error (message "Fontifying stealthily... %s" data)))))
701
702 ;; In XEmacs 19.14 with pre-idle-hook we do not have to call this.
703 (defun lazy-lock-post-resize-fontify-windows (frame)
704 ;; Fontify all windows in FRAME.
705 (let ((lazy-lock-walk-windows t) executing-kbd-macro this-command)
706 (save-excursion
707 (save-selected-window
708 (select-frame frame)
709 (lazy-lock-pre-idle-fontify-windows)))))
710
711 (defun lazy-lock-post-setup-emacs-fontify-windows ()
712 ;; Fontify all windows in all frames.
713 (let ((lazy-lock-walk-windows 'all-frames) executing-kbd-macro this-command)
714 (lazy-lock-pre-idle-fontify-windows)))
715
716 (defun lazy-lock-post-setup-ediff-control-frame ()
717 ;; Fontify all windows in all frames when using the Ediff control frame.
718 (make-local-variable 'lazy-lock-walk-windows)
719 (setq lazy-lock-walk-windows (if (ediff-multiframe-setup-p) 'all-frames t))
720 (lazy-lock-fixup-hooks))
721
722 ;; Functions for fontification:
723
724 (defun lazy-lock-fontify-window ()
725 ;; Fontify the visible part of the buffer where necessary.
726 (let ((ws (if lazy-lock-hide-invisible
727 (save-excursion
728 (end-of-line) (forward-line (- (window-height))) (point))
729 (min (max (window-start) (point-min)) (point-max))))
730 (we (if lazy-lock-hide-invisible
731 (save-excursion
732 (end-of-line) (forward-line (window-height)) (point))
733 (min (max (1- (window-end)) (point-min)) (point-max)))))
734 (if (or (/= ws lazy-lock-cache-start) (/= we lazy-lock-cache-end))
735 ;; Find where we haven't `fontified' before.
736 (let* ((start (or (text-property-not-all ws we 'fontified t) ws))
737 (end (or (text-property-any start we 'fontified t) we))
738 (modified (buffer-modified-p)) (inhibit-read-only t)
739 ;; We do the following to prevent: undo list addition; region
740 ;; highlight disappearance; supersession/locking checks.
741 (buffer-undo-list t)
742 deactivate-mark buffer-file-name buffer-file-truename
743 ;; Ensure Emacs 19.30 syntactic fontification is always correct.
744 font-lock-beginning-of-syntax-function
745 ;; Prevent XEmacs 19.13 during fontification from messages.
746 font-lock-verbose)
747 (while (< start end)
748 ;; Fontify and flag the region as `fontified'.
749 ;; XEmacs: need to bind `font-lock-always-fontify-immediately'
750 ;; or we'll mess up in the presence of deferred font-locking.
751 (let ((font-lock-always-fontify-immediately t))
752 (font-lock-after-change-function start end 0))
753 (lazy-lock-put-text-property start end 'fontified t)
754 ;; Find the next region.
755 (setq start (or (text-property-not-all ws we 'fontified t) ws)
756 end (or (text-property-any start we 'fontified t) we)))
757 (setq lazy-lock-cache-start ws lazy-lock-cache-end we)
758 (or modified (set-buffer-modified-p nil))))))
759
760 (defun lazy-lock-fontify-walk-windows ()
761 ;; Fontify windows in all required by walking through them.
762 (save-excursion
763 (save-selected-window
764 (condition-case nil
765 (walk-windows
766 (function (lambda (window)
767 (select-window window)
768 (if lazy-lock-mode (lazy-lock-fontify-window))))
769 'no-minibuf (eq lazy-lock-walk-windows 'all-frames))
770 (wrong-type-argument
771 ;; Looks like the Emacs 19.28 Garbage Collection bug has hit town.
772 ;; Completely remove all text properties and restart.
773 (set-text-properties (point-min) (point-max) nil)
774 (turn-on-lazy-lock)
775 (lazy-lock-fontify-window)
776 (message "Fontifying window... done. (Restarted in %s)"
777 (buffer-name)))))))
778
779 (defun lazy-lock-fontify-stealthily ()
780 ;; Fontify an invisible part of the buffer where necessary.
781 (save-excursion
782 ;; Move to the end in case the character to the left is not `fontified'.
783 (end-of-line)
784 ;; Find where the next and previous regions not `fontified' begin and end.
785 (let ((next (text-property-not-all (point) (point-max) 'fontified t))
786 (prev (let ((p (previous-single-property-change (point) 'fontified)))
787 (and p (> p (point-min)) p)))
788 (modified (buffer-modified-p)) (inhibit-read-only t) start end
789 ;; We do the following to prevent: undo list addition; region
790 ;; highlight disappearance; supersession/locking checks.
791 (buffer-undo-list t)
792 deactivate-mark buffer-file-name buffer-file-truename
793 ;; Ensure Emacs 19.30 syntactic fontification is always correct.
794 font-lock-beginning-of-syntax-function
795 ;; Prevent XEmacs 19.13 during fontification from spewing messages.
796 font-lock-verbose)
797 (cond ((and (null next) (null prev))
798 ;; Nothing has been `fontified' yet.
799 (beginning-of-line 1) (setq start (point))
800 (forward-line (or lazy-lock-stealth-lines (window-height)))
801 (setq end (point)))
802 ((or (null prev)
803 (and next (> (- (point) prev) (- next (point)))))
804 ;; The next region is the nearest not `fontified'.
805 (goto-char next) (beginning-of-line 1) (setq start (point))
806 (forward-line (or lazy-lock-stealth-lines (window-height)))
807 ;; Maybe the region is already partially `fontified'.
808 (setq end (or (text-property-any next (point) 'fontified t)
809 (point))))
810 (t
811 ;; The previous region is the nearest not `fontified'.
812 (goto-char prev) (forward-line 1) (setq end (point))
813 (forward-line (- (or lazy-lock-stealth-lines (window-height))))
814 ;; Maybe the region is already partially `fontified'.
815 (setq start
816 (or (previous-single-property-change prev 'fontified nil (point))
817 (point)))))
818 ;; Fontify and flag the region as `fontified'.
819 ;; XEmacs: need to bind `font-lock-always-fontify-immediately'
820 ;; or we'll mess up in the presence of deferred font-locking.
821 (let ((font-lock-always-fontify-immediately t))
822 (font-lock-after-change-function start end 0))
823 (lazy-lock-put-text-property start end 'fontified t)
824 (or modified (set-buffer-modified-p nil)))))
825
826 (defun lazy-lock-fontify-walk-stealthily ()
827 ;; Fontify regions in all required buffers while there is no input.
828 (let ((buffers (buffer-list)) (continue t) fontified message-log-max)
829 (save-excursion
830 (while (and buffers continue)
831 (set-buffer (car buffers))
832 (if (and lazy-lock-mode (lazy-lock-unfontified-p))
833 ;; Fontify regions in this buffer while there is no input.
834 (let ((bufname (buffer-name)))
835 (if (and lazy-lock-stealth-verbose (not fontified))
836 (message "Fontifying stealthily..."))
837 ;; We `save-restriction' and `widen' around everything as
838 ;; `lazy-lock-fontify-stealthily' doesn't and we `sit-for'.
839 (save-restriction (widen) (lazy-lock-fontify-stealthily))
840 (while (and (lazy-lock-unfontified-p)
841 (setq continue (lazy-lock-sit-for
842 lazy-lock-stealth-nice)))
843 (if lazy-lock-stealth-verbose
844 (message "Fontifying stealthily... %2d%% of %s"
845 (lazy-lock-percent-fontified) bufname))
846 (save-restriction (widen) (lazy-lock-fontify-stealthily)))
847 ;; Note that fontification occurred.
848 (setq fontified t)))
849 (setq buffers (cdr buffers))))
850 (if (and lazy-lock-stealth-verbose fontified)
851 (message "Fontifying stealthily... %s." (if continue "done" "quit")))))
852
853 (defun lazy-lock-unfontified-p ()
854 ;; Return non-nil if there is anywhere still to be `fontified'.
855 (save-restriction
856 (widen)
857 (text-property-not-all (point-min) (point-max) 'fontified t)))
858
859 (defun lazy-lock-percent-fontified ()
860 ;; Return the percentage (of characters) of the buffer that are `fontified'.
861 (save-restriction
862 (widen)
863 (let ((size 0) (start (point-min)) (max (point-max)) end)
864 (while (setq start (text-property-any start max 'fontified t))
865 (setq end (or (text-property-not-all start max 'fontified t) max)
866 size (+ size (- end start))
867 start end))
868 ;; Saying "99% done" is probably better than "100% done" when it isn't.
869 (truncate (/ (* size 100.0) (buffer-size))))))
870
871 (defun lazy-lock-colour-invisible ()
872 ;; Fontify the current buffer in `lazy-lock-invisible-face'.
873 (save-restriction
874 (widen)
875 (let ((face 'lazy-lock-invisible-face)
876 (fore (if (stringp lazy-lock-invisible-foreground)
877 lazy-lock-invisible-foreground
878 (cdr (assq 'background-color (frame-parameters)))))
879 (modified (buffer-modified-p)) (inhibit-read-only t)
880 (buffer-undo-list t)
881 deactivate-mark buffer-file-name buffer-file-truename)
882 (make-face face)
883 (if (not (equal (face-foreground face) fore))
884 (condition-case nil
885 (set-face-foreground face fore)
886 (error (message "Unable to use foreground \"%s\"" fore))))
887 (lazy-lock-put-text-property (point-min) (point-max) 'face face)
888 (lazy-lock-put-text-property (point-min) (point-max) 'fontified nil)
889 (or modified (set-buffer-modified-p nil)))))
890
891 ;; Functions for Emacs:
892
893 ;; This fix is for a number of bugs in the function in Emacs 19.28.
894 (if (and (not lazy-lock-running-xemacs-p)
895 (not (emacs-version>= 19 29)))
896 (defun font-lock-fontify-region (start end &optional loudly)
897 "Put proper face on each string and comment between START and END."
898 (save-excursion
899 (save-restriction
900 (widen)
901 (goto-char start)
902 (beginning-of-line)
903 (if loudly (message "Fontifying %s... (syntactically...)" (buffer-name)))
904 (let ((inhibit-read-only t) (buffer-undo-list t)
905 buffer-file-name buffer-file-truename
906 (modified (buffer-modified-p))
907 (old-syntax (syntax-table))
908 (synstart (if comment-start-skip
909 (concat "\\s\"\\|" comment-start-skip)
910 "\\s\""))
911 (comstart (if comment-start-skip
912 (concat "\\s<\\|" comment-start-skip)
913 "\\s<"))
914 (startline (point))
915 state prev prevstate)
916 (unwind-protect
917 (progn
918 (if font-lock-syntax-table
919 (set-syntax-table font-lock-syntax-table))
920 ;; Find the state at the line-beginning before START.
921 (if (eq startline font-lock-cache-position)
922 (setq state font-lock-cache-state)
923 ;; Find outermost containing sexp.
924 (beginning-of-defun)
925 ;; Find the state at STARTLINE.
926 (while (< (point) startline)
927 (setq state (parse-partial-sexp (point) startline 0)))
928 (setq font-lock-cache-state state
929 font-lock-cache-position (point)))
930 ;; Now find the state precisely at START.
931 (setq state (parse-partial-sexp (point) start nil nil state))
932 ;; If the region starts inside a string, show the extent of it.
933 (if (nth 3 state)
934 (let ((beg (point)))
935 (while (and (re-search-forward "\\s\"" end 'move)
936 (nth 3 (parse-partial-sexp beg (point) nil nil
937 state))))
938 (lazy-lock-put-text-property
939 beg (point) 'face font-lock-string-face)
940 (setq state (parse-partial-sexp beg (point)
941 nil nil state))))
942 ;; Likewise for a comment.
943 (if (or (nth 4 state) (nth 7 state))
944 (let ((beg (point)))
945 (save-restriction
946 (narrow-to-region (point-min) end)
947 (condition-case nil
948 (progn
949 (re-search-backward comstart (point-min) 'move)
950 (forward-comment 1)
951 ;; forward-comment skips all whitespace,
952 ;; so go back to the real end of the comment.
953 (skip-chars-backward " \t"))
954 (error (goto-char end))))
955 (lazy-lock-put-text-property beg (point) 'face
956 font-lock-comment-face)
957 (setq state (parse-partial-sexp beg (point)
958 nil nil state))))
959 ;; Find each interesting place between here and END.
960 (while (and (< (point) end)
961 (setq prev (point) prevstate state)
962 (re-search-forward synstart end t)
963 (progn
964 ;; Clear out the fonts of what we skip over.
965 (remove-text-properties prev (point) '(face nil))
966 ;; Verify the state at that place
967 ;; so we don't get fooled by \" or \;.
968 (setq state (parse-partial-sexp prev (point)
969 nil nil state))))
970 (let ((here (point)))
971 (if (or (nth 4 state) (nth 7 state))
972 ;; We found a real comment start.
973 (let ((beg (match-beginning 0)))
974 (goto-char beg)
975 (save-restriction
976 (narrow-to-region (point-min) end)
977 (condition-case nil
978 (progn
979 (forward-comment 1)
980 ;; forward-comment skips all whitespace,
981 ;; so go back to the real end of the comment.
982 (skip-chars-backward " \t"))
983 (error (goto-char end))))
984 (lazy-lock-put-text-property
985 beg (point) 'face font-lock-comment-face)
986 (setq state (parse-partial-sexp here (point)
987 nil nil state)))
988 (if (nth 3 state)
989 (let ((beg (match-beginning 0)))
990 (while (and (re-search-forward "\\s\"" end 'move)
991 (nth 3 (parse-partial-sexp
992 here (point) nil nil state))))
993 (lazy-lock-put-text-property
994 beg (point) 'face font-lock-string-face)
995 (setq state (parse-partial-sexp here (point)
996 nil nil state))))))
997 ;; Make sure PREV is non-nil after the loop
998 ;; only if it was set on the very last iteration.
999 (setq prev nil)))
1000 (set-syntax-table old-syntax)
1001 (and prev
1002 (remove-text-properties prev end '(face nil)))
1003 (and (buffer-modified-p)
1004 (not modified)
1005 (set-buffer-modified-p nil))))))))
1006
1007 ;; Functions for XEmacs:
1008
1009 ;; These fix bugs in `text-property-any' and `text-property-not-all'. They may
1010 ;; not work perfectly in 19.11 and below because `next-single-property-change'
1011 ;; is also broke and not easily fixable in Lisp.
1012 (if (and lazy-lock-running-xemacs-p
1013 (not (emacs-version>= 19 12)))
1014 (progn
1015 ;; Loop through property changes until found. This fix includes a work
1016 ;; around which prevents a bug in `window-start' causing a barf here.
1017 (defun text-property-any (start end prop value &optional buffer)
1018 "Check text from START to END to see if PROP is ever `eq' to VALUE.
1019 If so, return the position of the first character whose PROP is `eq'
1020 to VALUE. Otherwise return nil."
1021 (let ((start (min start end)) (end (max start end)))
1022 (while (and start (not (eq (get-text-property start prop buffer) value)))
1023 (setq start (next-single-property-change start prop buffer end)))
1024 start))
1025 ;; No need to loop here; if it's not at START it's at the next change.
1026 ;; However, `next-single-property-change' sometimes returns LIMIT, or
1027 ;; `point-max', if no change is found and sometimes returns nil.
1028 (defun text-property-not-all (start end prop value &optional buffer)
1029 "Check text from START to END to see if PROP is ever not `eq' to VALUE.
1030 If so, return the position of the first character whose PROP is not
1031 `eq' to VALUE. Otherwise, return nil."
1032 (if (not (eq value (get-text-property start prop buffer)))
1033 start
1034 (let ((next (next-single-property-change start prop buffer end))
1035 (end (or end (save-excursion (and buffer (set-buffer buffer))
1036 (point-max)))))
1037 (and next (< next end) next))))))
1038
1039 ;; XEmacs 19.11 function `font-lock-any-extents-p' looks for `text-prop' rather
1040 ;; than `face'. Since `font-lock-unfontify-region' only removes `face', and we
1041 ;; have non-font-lock properties hanging about, `text-prop' never gets removed.
1042 ;; Unfortunately `font-lock-any-extents-p' is inlined so we can't redefine it.
1043 (if (and lazy-lock-running-xemacs-p
1044 (not (emacs-version>= 19 12)))
1045 (add-hook 'font-lock-mode-hook
1046 (function (lambda ()
1047 (remove-hook 'after-change-functions 'font-lock-after-change-function)
1048 (add-hook 'after-change-functions
1049 (function (lambda (beg end old-len)
1050 (let ((a-c-beg beg) (a-c-end end))
1051 (save-excursion
1052 ;; First set `text-prop' to nil for `font-lock-any-extents-p'.
1053 (goto-char end) (forward-line 1) (setq end (point))
1054 (goto-char beg) (beginning-of-line) (setq beg (point))
1055 (lazy-lock-put-text-property beg end 'text-prop nil)
1056 ;; Then do the real `font-lock-after-change-function'.
1057 (font-lock-after-change-function a-c-beg a-c-end old-len)
1058 ;; Now set `fontified' to t to stop `lazy-lock-fontify-window'.
1059 (lazy-lock-put-text-property beg end 'fontified t))))))))))
1060
1061 (if (and lazy-lock-running-xemacs-p (emacs-version>= 19 12))
1062 ;; XEmacs 19.12 font-lock.el's `font-lock-fontify-buffer' runs a hook.
1063 (add-hook 'font-lock-after-fontify-buffer-hook
1064 'lazy-lock-after-fontify-buffer))
1065
1066 ;; Cope with the differences between Emacs and [LX]Emacs.
1067 (or (fboundp 'frame-parameters)
1068 (defalias 'frame-parameters 'screen-parameters))
1069
1070 ;; Install ourselves:
1071
1072 ;; We don't install ourselves on `font-lock-mode-hook' as other packages can be
1073 ;; used with font-lock.el, and lazy-lock.el should be dumpable without forcing
1074 ;; people to get lazy or making it difficult for people to use alternatives.
1075 ;; make sure we add after font-lock's own pre-idle-hook.
1076 (add-hook 'window-setup-hook 'lazy-lock-post-setup-emacs-fontify-windows)
1077 ;Not needed in XEmacs 19.14:
1078 ;(add-hook 'window-size-change-functions 'lazy-lock-post-resize-fontify-windows)
1079
1080 ;; Package-specific.
1081 (add-hook 'ediff-after-setup-control-frame-hooks
1082 'lazy-lock-post-setup-ediff-control-frame)
1083
1084 ;; Might as well uninstall too. Package-local symbols would be nice...
1085 (and (fboundp 'unintern) (unintern 'lazy-lock-running-xemacs-p))
1086 (and (fboundp 'unintern) (unintern 'lazy-lock-sit-for))
1087
1088 ;; Maybe save on the modeline?
1089 ;;(setcdr (assq 'font-lock-mode minor-mode-alist) '(" Lazy"))
1090
1091 ;(or (assq 'lazy-lock-mode minor-mode-alist)
1092 ; (setq minor-mode-alist (cons '(lazy-lock-mode " Lazy") minor-mode-alist)))
1093
1094 ;; XEmacs change: do it the right way. This works with modeline mousing.
1095 ;;;###autoload
1096 (add-minor-mode 'lazy-lock-mode " Lazy")
1097
1098 ;; Provide ourselves:
1099
1100 (provide 'lazy-lock)
1101
1102 ;;; lazy-lock.el ends here