Remove trailing ^M that prevent CVS-merging.
[bpt/emacs.git] / lisp / jit-lock.el
CommitLineData
7840ced1
GM
1;;; jit-lock.el --- just-in-time fontification.
2
3;; Copyright (C) 1998 Free Software Foundation, Inc.
4
5;; Author: Gerd Moellmann <gerd@gnu.org>
6;; Keywords: faces files
7;; Version: 1.0
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;; Just-in-time fontification, triggered by C redisplay code.
29
30;;; Code:
31
32
33(require 'font-lock)
34
35(eval-when-compile
60bffb78
GM
36 (defmacro with-buffer-unmodified (&rest body)
37 "Eval BODY, preserving the current buffer's modified state."
38 (let ((modified (make-symbol "modified")))
39 `(let ((,modified (buffer-modified-p)))
40 ,@body
25fbf2c4
GM
41 (unless ,modified
42 (restore-buffer-modified-p nil)))))
60bffb78 43
7840ced1
GM
44 (defmacro with-buffer-prepared-for-font-lock (&rest body)
45 "Execute BODY in current buffer, overriding several variables.
46Preserves the `buffer-modified-p' state of the current buffer."
9f1a8fb4
GM
47 `(with-buffer-unmodified
48 (let ((buffer-undo-list t)
49 (inhibit-read-only t)
50 (inhibit-point-motion-hooks t)
51 before-change-functions
52 after-change-functions
53 deactivate-mark
54 buffer-file-name
55 buffer-file-truename)
56 ,@body))))
7840ced1 57
60bffb78 58
7840ced1
GM
59\f
60;;; Customization.
61
62(defcustom jit-lock-chunk-size 500
63 "*Font-lock chunks of this many characters, or smaller."
64 :type 'integer
65 :group 'jit-lock)
66
67
68(defcustom jit-lock-stealth-time 3
69 "*Time in seconds to wait before beginning stealth fontification.
70Stealth fontification occurs if there is no input within this time.
71If nil, means stealth fontification is never performed.
72
73The value of this variable is used when JIT Lock mode is turned on."
74 :type '(choice (const :tag "never" nil)
75 (number :tag "seconds"))
76 :group 'jit-lock)
77
78
79(defcustom jit-lock-stealth-nice 0.125
80 "*Time in seconds to pause between chunks of stealth fontification.
81Each iteration of stealth fontification is separated by this amount of time,
82thus reducing the demand that stealth fontification makes on the system.
83If nil, means stealth fontification is never paused.
84To reduce machine load during stealth fontification, at the cost of stealth
85taking longer to fontify, you could increase the value of this variable.
86See also `jit-lock-stealth-load'."
87 :type '(choice (const :tag "never" nil)
88 (number :tag "seconds"))
89 :group 'jit-lock)
90
91
92(defcustom jit-lock-stealth-load
93 (if (condition-case nil (load-average) (error)) 200)
94 "*Load in percentage above which stealth fontification is suspended.
95Stealth fontification pauses when the system short-term load average (as
96returned by the function `load-average' if supported) goes above this level,
97thus reducing the demand that stealth fontification makes on the system.
98If nil, means stealth fontification is never suspended.
99To reduce machine load during stealth fontification, at the cost of stealth
100taking longer to fontify, you could reduce the value of this variable.
101See also `jit-lock-stealth-nice'."
102 :type (if (condition-case nil (load-average) (error))
103 '(choice (const :tag "never" nil)
104 (integer :tag "load"))
105 '(const :format "%t: unsupported\n" nil))
106 :group 'jit-lock)
107
108
109(defcustom jit-lock-stealth-verbose nil
110 "*If non-nil, means stealth fontification should show status messages."
111 :type 'boolean
112 :group 'jit-lock)
113
114
115(defcustom jit-lock-defer-contextually 'syntax-driven
116 "*If non-nil, means deferred fontification should be syntactically true.
117If nil, means deferred fontification occurs only on those lines modified. This
118means where modification on a line causes syntactic change on subsequent lines,
119those subsequent lines are not refontified to reflect their new context.
120If t, means deferred fontification occurs on those lines modified and all
121subsequent lines. This means those subsequent lines are refontified to reflect
122their new syntactic context, either immediately or when scrolling into them.
123If any other value, e.g., `syntax-driven', means deferred syntactically true
124fontification occurs only if syntactic fontification is performed using the
125buffer mode's syntax table, i.e., only if `font-lock-keywords-only' is nil.
126
127The value of this variable is used when JIT Lock mode is turned on."
128 :type '(choice (const :tag "never" nil)
129 (const :tag "always" t)
130 (other :tag "syntax-driven" syntax-driven))
131 :group 'jit-lock)
132
133
134\f
135;;; Variables that are not customizable.
136
137(defvar jit-lock-mode nil
138 "Non-nil means Just-in-time Lock mode is active.")
139(make-variable-buffer-local 'jit-lock-mode)
140
141
142(defvar jit-lock-first-unfontify-pos nil
143 "Consider text after this position as unfontified.")
144(make-variable-buffer-local 'jit-lock-first-unfontify-pos)
145
146
147(defvar jit-lock-stealth-timer nil
148 "Timer for stealth fontification in Just-in-time Lock mode.")
149
02b420eb
SM
150(defvar jit-lock-saved-fontify-buffer-function nil
151 "Value of `font-lock-fontify-buffer-function' before jit-lock's activation.")
7840ced1
GM
152
153\f
154;;; JIT lock mode
155
156;;;###autoload
157(defun jit-lock-mode (arg)
158 "Toggle Just-in-time Lock mode.
159With arg, turn Just-in-time Lock mode on if and only if arg is positive.
160Enable it automatically by customizing group `font-lock'.
161
162When Just-in-time Lock mode is enabled, fontification is different in the
163following ways:
164
165- Demand-driven buffer fontification triggered by Emacs C code.
166 This means initial fontification of the whole buffer does not occur.
167 Instead, fontification occurs when necessary, such as when scrolling
168 through the buffer would otherwise reveal unfontified areas. This is
169 useful if buffer fontification is too slow for large buffers.
170
171- Stealthy buffer fontification if `jit-lock-stealth-time' is non-nil.
172 This means remaining unfontified areas of buffers are fontified if Emacs has
173 been idle for `jit-lock-stealth-time' seconds, while Emacs remains idle.
174 This is useful if any buffer has any deferred fontification.
175
176- Deferred context fontification if `jit-lock-defer-contextually' is
177 non-nil. This means fontification updates the buffer corresponding to
178 true syntactic context, after `jit-lock-stealth-time' seconds of Emacs
179 idle time, while Emacs remains idle. Otherwise, fontification occurs
180 on modified lines only, and subsequent lines can remain fontified
181 corresponding to previous syntactic contexts. This is useful where
182 strings or comments span lines.
183
184Stealth fontification only occurs while the system remains unloaded.
185If the system load rises above `jit-lock-stealth-load' percent, stealth
186fontification is suspended. Stealth fontification intensity is controlled via
02b420eb 187the variable `jit-lock-stealth-nice'."
7840ced1
GM
188 (interactive "P")
189 (setq jit-lock-mode (if arg
190 (> (prefix-numeric-value arg) 0)
191 (not jit-lock-mode)))
192 (cond ((and jit-lock-mode
193 (or (not (boundp 'font-lock-mode))
194 (not font-lock-mode)))
195 ;; If font-lock is not on, turn it on, with Just-in-time
196 ;; Lock mode as support mode; font-lock will call us again.
197 (let ((font-lock-support-mode 'jit-lock-mode))
198 (font-lock-mode t)))
199
200 ;; Turn Just-in-time Lock mode on.
201 (jit-lock-mode
202 ;; Setting `font-lock-fontified' makes font-lock believe the
203 ;; buffer is already fontified, so that it won't highlight
02b420eb 204 ;; the whole buffer or bail out on a large buffer.
7840ced1
GM
205 (make-local-variable 'font-lock-fontified)
206 (setq font-lock-fontified t)
207
02b420eb
SM
208 ;; Setup JIT font-lock-fontify-buffer.
209 (unless jit-lock-saved-fontify-buffer-function
210 (set (make-local-variable 'jit-lock-saved-fontify-buffer-function)
211 font-lock-fontify-buffer-function)
212 (set (make-local-variable 'font-lock-fontify-buffer-function)
213 'jit-lock-fontify-buffer))
214
7840ced1
GM
215 (setq jit-lock-first-unfontify-pos nil)
216
217 ;; Install an idle timer for stealth fontification.
218 (when (and jit-lock-stealth-time
219 (null jit-lock-stealth-timer))
02b420eb 220 (setq jit-lock-stealth-timer
7840ced1
GM
221 (run-with-idle-timer jit-lock-stealth-time
222 jit-lock-stealth-time
223 'jit-lock-stealth-fontify)))
224
225 ;; Add a hook for deferred contectual fontification.
226 (when (or (eq jit-lock-defer-contextually 'always)
227 (and (not (eq jit-lock-defer-contextually 'never))
228 (null font-lock-keywords-only)))
659451a2 229 (add-hook 'after-change-functions 'jit-lock-after-change nil t))
7840ced1
GM
230
231 ;; Install the fontification hook.
232 (add-hook 'fontification-functions 'jit-lock-function))
233
234 ;; Turn Just-in-time Lock mode off.
235 (t
236 ;; Cancel our idle timer.
237 (when jit-lock-stealth-timer
238 (cancel-timer jit-lock-stealth-timer)
239 (setq jit-lock-stealth-timer nil))
240
02b420eb
SM
241 ;; Restore non-JIT font-lock-fontify-buffer.
242 (when jit-lock-saved-fontify-buffer-function
243 (set (make-local-variable 'font-lock-fontify-buffer-function)
244 jit-lock-saved-fontify-buffer-function)
245 (setq jit-lock-saved-fontify-buffer-function nil))
246
7840ced1 247 ;; Remove hooks.
02b420eb 248 (remove-hook 'after-change-functions 'jit-lock-after-change t)
7840ced1
GM
249 (remove-hook 'fontification-functions 'jit-lock-function))))
250
251
252;;;###autoload
253(defun turn-on-jit-lock ()
254 "Unconditionally turn on Just-in-time Lock mode."
255 (jit-lock-mode 1))
256
02b420eb
SM
257;; This function is used to prevent font-lock-fontify-buffer from
258;; fontifying eagerly the whole buffer. This is important for
259;; things like CWarn mode which adds/removes a few keywords and
260;; does a refontify (which takes ages on large files).
261(defun jit-lock-fontify-buffer ()
262 (if (not (and font-lock-mode jit-lock-mode))
263 (funcall jit-lock-saved-fontify-buffer-function)
264 (with-buffer-prepared-for-font-lock
265 (save-restriction
266 (widen)
267 (add-text-properties (point-min) (point-max) '(fontified nil))))))
7840ced1
GM
268
269\f
270;;; On demand fontification.
271
272(defun jit-lock-function (start)
273 "Fontify current buffer starting at position START.
274This function is added to `fontification-functions' when `jit-lock-mode'
275is active."
276 (when jit-lock-mode
9f1a8fb4 277 (jit-lock-function-1 start)))
60bffb78
GM
278
279
280(defun jit-lock-function-1 (start)
02b420eb 281 "Fontify current buffer starting at position START."
60bffb78
GM
282 (with-buffer-prepared-for-font-lock
283 (save-excursion
284 (save-restriction
285 (widen)
286 (let ((end (min (point-max) (+ start jit-lock-chunk-size)))
287 (parse-sexp-lookup-properties font-lock-syntactic-keywords)
288 (font-lock-beginning-of-syntax-function nil)
289 (old-syntax-table (syntax-table))
290 next font-lock-start font-lock-end)
291 (when font-lock-syntax-table
292 (set-syntax-table font-lock-syntax-table))
293 (save-match-data
294 (condition-case error
295 ;; Fontify chunks beginning at START. The end of a
296 ;; chunk is either `end', or the start of a region
297 ;; before `end' that has already been fontified.
298 (while start
299 ;; Determine the end of this chunk.
300 (setq next (or (text-property-any start end 'fontified t)
301 end))
302
303 ;; Decide which range of text should be fontified.
304 ;; The problem is that START and NEXT may be in the
305 ;; middle of something matched by a font-lock regexp.
306 ;; Until someone has a better idea, let's start
307 ;; at the start of the line containing START and
308 ;; stop at the start of the line following NEXT.
309 (goto-char next)
310 (setq font-lock-end (line-beginning-position 2))
311 (goto-char start)
312 (setq font-lock-start (line-beginning-position))
7840ced1 313
60bffb78
GM
314 ;; Fontify the chunk, and mark it as fontified.
315 (font-lock-fontify-region font-lock-start font-lock-end nil)
316 (add-text-properties start next '(fontified t))
7840ced1 317
60bffb78
GM
318 ;; Find the start of the next chunk, if any.
319 (setq start (text-property-any next end 'fontified nil)))
7840ced1 320
60bffb78
GM
321 ((error quit)
322 (message "Fontifying region...%s" error))))
7840ced1 323
60bffb78
GM
324 ;; Restore previous buffer settings.
325 (set-syntax-table old-syntax-table))))))
7840ced1
GM
326
327
328(defun jit-lock-after-fontify-buffer ()
329 "Mark the current buffer as fontified.
330Called from `font-lock-after-fontify-buffer."
331 (with-buffer-prepared-for-font-lock
332 (add-text-properties (point-min) (point-max) '(fontified t))))
333
334
335(defun jit-lock-after-unfontify-buffer ()
336 "Mark the current buffer as unfontified.
337Called from `font-lock-after-fontify-buffer."
338 (with-buffer-prepared-for-font-lock
339 (remove-text-properties (point-min) (point-max) '(fontified nil))))
340
341
342\f
343;;; Stealth fontification.
344
345(defsubst jit-lock-stealth-chunk-start (around)
346 "Return the start of the next chunk to fontify around position AROUND..
347Value is nil if there is nothing more to fontify."
8c887c51
GM
348 (if (zerop (buffer-size))
349 nil
350 (save-restriction
351 (widen)
352 (let* ((next (text-property-any around (point-max) 'fontified nil))
353 (prev (previous-single-property-change around 'fontified))
354 (prop (get-text-property (max (point-min) (1- around))
355 'fontified))
356 (start (cond
357 ((null prev)
358 ;; There is no property change between AROUND
359 ;; and the start of the buffer. If PROP is
360 ;; non-nil, everything in front of AROUND is
361 ;; fontified, otherwise nothing is fontified.
362 (if prop
363 nil
364 (max (point-min)
365 (- around (/ jit-lock-chunk-size 2)))))
366 (prop
367 ;; PREV is the start of a region of fontified
368 ;; text containing AROUND. Start fontfifying a
369 ;; chunk size before the end of the unfontified
370 ;; region in front of that.
371 (max (or (previous-single-property-change prev 'fontified)
372 (point-min))
373 (- prev jit-lock-chunk-size)))
374 (t
375 ;; PREV is the start of a region of unfontified
376 ;; text containing AROUND. Start at PREV or
377 ;; chunk size in front of AROUND, whichever is
378 ;; nearer.
379 (max prev (- around jit-lock-chunk-size)))))
380 (result (cond ((null start) next)
381 ((null next) start)
382 ((< (- around start) (- next around)) start)
383 (t next))))
384 result))))
385
7840ced1
GM
386
387(defun jit-lock-stealth-fontify ()
388 "Fontify buffers stealthily.
389This functions is called after Emacs has been idle for
390`jit-lock-stealth-time' seconds."
391 (unless (or executing-kbd-macro
392 (window-minibuffer-p (selected-window)))
393 (let ((buffers (buffer-list))
394 minibuffer-auto-raise
395 message-log-max)
8c887c51 396 (while (and buffers (not (input-pending-p)))
7840ced1
GM
397 (let ((buffer (car buffers)))
398 (setq buffers (cdr buffers))
8c887c51 399
7840ced1
GM
400 (with-current-buffer buffer
401 (when jit-lock-mode
402 ;; This is funny. Calling sit-for with 3rd arg non-nil
403 ;; so that it doesn't redisplay, internally calls
404 ;; wait_reading_process_input also with a parameter
405 ;; saying "don't redisplay." Since this function here
406 ;; is called periodically, this effectively leads to
407 ;; process output not being redisplayed at all because
408 ;; redisplay_internal is never called. (That didn't
409 ;; work in the old redisplay either.) So, we learn that
410 ;; we mustn't call sit-for that way here. But then, we
411 ;; have to be cautious not to call sit-for in a widened
412 ;; buffer, since this could display hidden parts of that
413 ;; buffer. This explains the seemingly weird use of
414 ;; save-restriction/widen here.
415
416 (with-temp-message (if jit-lock-stealth-verbose
417 (concat "JIT stealth lock "
418 (buffer-name)))
8c887c51 419
9f1a8fb4
GM
420 ;; Perform deferred unfontification, if any.
421 (when jit-lock-first-unfontify-pos
422 (save-restriction
423 (widen)
424 (when (and (>= jit-lock-first-unfontify-pos (point-min))
425 (< jit-lock-first-unfontify-pos (point-max)))
426 (with-buffer-prepared-for-font-lock
427 (put-text-property jit-lock-first-unfontify-pos
428 (point-max) 'fontified nil))
429 (setq jit-lock-first-unfontify-pos nil))))
430
431 ;; In the following code, the `sit-for' calls cause a
432 ;; redisplay, so it's required that the
433 ;; buffer-modified flag of a buffer that is displayed
434 ;; has the right value---otherwise the mode line of
435 ;; an unmodified buffer would show a `*'.
436 (let (start
437 (nice (or jit-lock-stealth-nice 0))
438 (point (point)))
439 (while (and (setq start
440 (jit-lock-stealth-chunk-start point))
441 (sit-for nice))
7840ced1 442
9f1a8fb4
GM
443 ;; Wait a little if load is too high.
444 (when (and jit-lock-stealth-load
445 (> (car (load-average)) jit-lock-stealth-load))
446 (sit-for (or jit-lock-stealth-time 30)))
7840ced1 447
9f1a8fb4
GM
448 ;; Unless there's input pending now, fontify.
449 (unless (input-pending-p)
450 (jit-lock-function-1 start))))))))))))
7840ced1
GM
451
452
453\f
454;;; Deferred fontification.
455
456(defun jit-lock-after-change (start end old-len)
457 "Mark the rest of the buffer as not fontified after a change.
458Installed on `after-change-functions'.
459START and END are the start and end of the changed text. OLD-LEN
460is the pre-change length.
461This function ensures that lines following the change will be refontified
462in case the syntax of those lines has changed. Refontification
463will take place when text is fontified stealthily."
464 ;; Don't do much here---removing text properties is too slow for
465 ;; fast typers, giving them the impression of Emacs not being
466 ;; very responsive.
467 (when jit-lock-mode
468 (setq jit-lock-first-unfontify-pos
469 (if jit-lock-first-unfontify-pos
470 (min jit-lock-first-unfontify-pos start)
471 start))))
472
473
474(provide 'jit-lock)
475
476;; jit-lock.el ends here