]> code.delx.au - gnu-emacs/blobdiff - lisp/jit-lock.el
(inferior-emacs-lisp-mode): Bind comint-dynamic-complete-functions locally.
[gnu-emacs] / lisp / jit-lock.el
index cf1261e365275a38ada5730e4e29ab3a6f3faacd..2f832bf3dad34e655c4154562bd3f8f5ac5acff2 100644 (file)
@@ -1,10 +1,9 @@
-;;; jit-lock.el --- just-in-time fontification.
+;;; jit-lock.el --- just-in-time fontification
 
-;; Copyright (C) 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
 
 ;; Author: Gerd Moellmann <gerd@gnu.org>
 ;; Keywords: faces files
-;; Version: 1.0
 
 ;; This file is part of GNU Emacs.
 
@@ -30,8 +29,6 @@
 ;;; Code:
 
 
-(require 'font-lock)
-
 (eval-when-compile
   (defmacro with-buffer-unmodified (&rest body)
     "Eval BODY, preserving the current buffer's modified state."
@@ -68,7 +65,7 @@ Preserves the `buffer-modified-p' state of the current buffer."
 (defcustom jit-lock-stealth-time 3
   "*Time in seconds to wait before beginning stealth fontification.
 Stealth fontification occurs if there is no input within this time.
-If nil, means stealth fontification is never performed.
+If nil, stealth fontification is never performed.
 
 The value of this variable is used when JIT Lock mode is turned on."
   :type '(choice (const :tag "never" nil)
@@ -130,7 +127,12 @@ The value of this variable is used when JIT Lock mode is turned on."
                 (other :tag "syntax-driven" syntax-driven))
   :group 'jit-lock)
 
-
+(defcustom jit-lock-defer-time nil ;; 0.25
+  "Idle time after which deferred fontification should take place.
+If nil, fontification is not deferred."
+  :group 'jit-lock
+  :type '(choice (const :tag "never" nil)
+                (number :tag "seconds")))
 \f
 ;;; Variables that are not customizable.
 
@@ -141,9 +143,10 @@ The value of this variable is used when JIT Lock mode is turned on."
 (defvar jit-lock-functions nil
   "Functions to do the actual fontification.
 They are called with two arguments: the START and END of the region to fontify.")
+(make-variable-buffer-local 'jit-lock-functions)
 
 (defvar jit-lock-first-unfontify-pos nil
-  "Consider text after this position as unfontified.
+  "Consider text after this position as contextually unfontified.
 If nil, contextual fontification is disabled.")
 (make-variable-buffer-local 'jit-lock-first-unfontify-pos)
 
@@ -151,13 +154,14 @@ If nil, contextual fontification is disabled.")
 (defvar jit-lock-stealth-timer nil
   "Timer for stealth fontification in Just-in-time Lock mode.")
 
-(defvar jit-lock-saved-fontify-buffer-function nil
-  "Value of `font-lock-fontify-buffer-function' before jit-lock's activation.") 
+(defvar jit-lock-defer-timer nil
+  "Timer for deferred fontification in Just-in-time Lock mode.")
 
+(defvar jit-lock-buffers nil
+  "List of buffers with pending deferred fontification.")
 \f
 ;;; JIT lock mode
 
-;;;###autoload
 (defun jit-lock-mode (arg)
   "Toggle Just-in-time Lock mode.
 Turn Just-in-time Lock mode on if and only if ARG is non-nil.
@@ -193,91 +197,78 @@ the variable `jit-lock-stealth-nice'."
   (cond (;; Turn Just-in-time Lock mode on.
         jit-lock-mode
 
-        ;; Mark the buffer for refontification
-        ;; (in case spurious `fontified' text-props were left around).
-        (jit-lock-fontify-buffer)
-
-        ;; Setting `font-lock-fontified' makes font-lock believe the
-        ;; buffer is already fontified, so that it won't highlight
-        ;; the whole buffer or bail out on a large buffer.
-        (set (make-local-variable 'font-lock-fontified) t)
-
-        ;; Setup JIT font-lock-fontify-buffer.
-        (unless jit-lock-saved-fontify-buffer-function
-          (set (make-local-variable 'jit-lock-saved-fontify-buffer-function)
-               font-lock-fontify-buffer-function)
-          (set (make-local-variable 'font-lock-fontify-buffer-function)
-               'jit-lock-fontify-buffer))
+        ;; Mark the buffer for refontification.
+        (jit-lock-refontify)
 
         ;; Install an idle timer for stealth fontification.
-        (when (and jit-lock-stealth-time
-                   (null jit-lock-stealth-timer))
+        (when (and jit-lock-stealth-time (null jit-lock-stealth-timer))
           (setq jit-lock-stealth-timer
-                (run-with-idle-timer jit-lock-stealth-time
-                                     jit-lock-stealth-time
+                (run-with-idle-timer jit-lock-stealth-time t
                                      'jit-lock-stealth-fontify)))
 
+        ;; Init deferred fontification timer.
+        (when (and jit-lock-defer-time (null jit-lock-defer-timer))
+          (setq jit-lock-defer-timer
+                (run-with-idle-timer jit-lock-defer-time t
+                                     'jit-lock-deferred-fontify)))
+
         ;; Initialize deferred contextual fontification if requested.
-        (when (or (eq jit-lock-defer-contextually 'always)
-                  (and (not (eq jit-lock-defer-contextually 'never))
-                       (boundp 'font-lock-keywords-only)
-                       (null font-lock-keywords-only)))
-          (setq jit-lock-first-unfontify-pos (point-max)))
-
-        ;; Setup our after-change-function
-        ;; and remove font-lock's (if any).
-        (remove-hook 'after-change-functions 'font-lock-after-change-function t)
+        (when (eq jit-lock-defer-contextually t)
+          (setq jit-lock-first-unfontify-pos
+                (or jit-lock-first-unfontify-pos (point-max))))
+
+        ;; Setup our hooks.
         (add-hook 'after-change-functions 'jit-lock-after-change nil t)
-        
-        ;; Install the fontification hook.
         (add-hook 'fontification-functions 'jit-lock-function))
 
        ;; Turn Just-in-time Lock mode off.
        (t
-        ;; Cancel our idle timer.
-        (when jit-lock-stealth-timer
-          (cancel-timer jit-lock-stealth-timer)
-          (setq jit-lock-stealth-timer nil))
-
-        ;; Restore non-JIT font-lock-fontify-buffer.
-        (when jit-lock-saved-fontify-buffer-function
-          (set (make-local-variable 'font-lock-fontify-buffer-function)
-               jit-lock-saved-fontify-buffer-function)
-          (setq jit-lock-saved-fontify-buffer-function nil))
-
-        ;; Remove hooks (and restore font-lock's if necessary).
+        ;; Cancel our idle timers.
+        (when (and (or jit-lock-stealth-timer jit-lock-defer-timer)
+                   ;; Only if there's no other buffer using them.
+                   (not (catch 'found
+                          (dolist (buf (buffer-list))
+                            (with-current-buffer buf
+                              (when jit-lock-mode (throw 'found t)))))))
+          (when jit-lock-stealth-timer
+            (cancel-timer jit-lock-stealth-timer)
+            (setq jit-lock-stealth-timer nil))
+          (when jit-lock-defer-timer
+            (cancel-timer jit-lock-defer-timer)
+            (setq jit-lock-defer-timer nil)))
+
+        ;; Remove hooks.
         (remove-hook 'after-change-functions 'jit-lock-after-change t)
-        (when font-lock-mode
-          (add-hook 'after-change-functions
-                    'font-lock-after-change-function nil t))
         (remove-hook 'fontification-functions 'jit-lock-function))))
 
-(defun jit-lock-register (fun)
+;;;###autoload
+(defun jit-lock-register (fun &optional contextual)
   "Register FUN as a fontification function to be called in this buffer.
 FUN will be called with two arguments START and END indicating the region
-that need to be (re)fontified."
+that needs to be (re)fontified.
+If non-nil, CONTEXTUAL means that a contextual fontification would be useful."
   (add-hook 'jit-lock-functions fun nil t)
+  (when (and contextual jit-lock-defer-contextually)
+    (set (make-local-variable 'jit-lock-defer-contextually) t))
   (jit-lock-mode t))
 
 (defun jit-lock-unregister (fun)
   "Unregister FUN as a fontification function.
 Only applies to the current buffer."
   (remove-hook 'jit-lock-functions fun t)
-  (when (or (null jit-lock-functions)
-           (and (equal jit-lock-functions '(t))
-                (null (default-value 'jit-lock-functions))))
-    (jit-lock-mode nil)))
+  (unless jit-lock-functions (jit-lock-mode nil)))
 
 ;; This function is used to prevent font-lock-fontify-buffer from
 ;; fontifying eagerly the whole buffer.  This is important for
 ;; things like CWarn mode which adds/removes a few keywords and
 ;; does a refontify (which takes ages on large files).
-(defun jit-lock-fontify-buffer ()
+(defun jit-lock-refontify (&optional beg end)
+  "Force refontification of the region BEG..END (default whole buffer)."
   (with-buffer-prepared-for-jit-lock
    (save-restriction
      (widen)
-     (add-text-properties (point-min) (point-max) '(fontified nil)))))
-
+     (put-text-property (or beg (point-min)) (or end (point-max))
+                       'fontified nil))))
 \f
 ;;; On demand fontification.
 
@@ -286,48 +277,63 @@ Only applies to the current buffer."
 This function is added to `fontification-functions' when `jit-lock-mode'
 is active."
   (when jit-lock-mode
-    (jit-lock-function-1 start)))
-     
-  
-(defun jit-lock-function-1 (start)
-  "Fontify current buffer starting at position START."
+    (if (null jit-lock-defer-time)
+       ;; No deferral.
+       (jit-lock-fontify-now start (+ start jit-lock-chunk-size))
+      ;; Record the buffer for later fontification.
+      (unless (memq (current-buffer) jit-lock-buffers)
+       (push (current-buffer) jit-lock-buffers))
+      ;; Mark the area as defer-fontified so that the redisplay engine
+      ;; is happy and so that the idle timer can find the places to fontify.
+      (with-buffer-prepared-for-jit-lock
+       (put-text-property start
+                         (next-single-property-change
+                          start 'fontified nil
+                          (min (point-max) (+ start jit-lock-chunk-size)))
+                         'fontified 'defer)))))
+
+(defun jit-lock-fontify-now (&optional start end)
+  "Fontify current buffer from START to END.
+Defaults to the whole buffer.  END can be out of bounds."
   (with-buffer-prepared-for-jit-lock
    (save-excursion
-     (save-restriction
-       (widen)
-       (let ((end (min (point-max) (+ start jit-lock-chunk-size)))
-            (font-lock-beginning-of-syntax-function nil)
-            next)
-        (save-match-data
-          ;; Fontify chunks beginning at START.  The end of a
-          ;; chunk is either `end', or the start of a region
-          ;; before `end' that has already been fontified.
-          (while start
-            ;; Determine the end of this chunk.
-            (setq next (or (text-property-any start end 'fontified t)
-                           end))
-
-            ;; Decide which range of text should be fontified.
-            ;; The problem is that START and NEXT may be in the
-            ;; middle of something matched by a font-lock regexp.
-            ;; Until someone has a better idea, let's start
-            ;; at the start of the line containing START and
-            ;; stop at the start of the line following NEXT.
-            (goto-char next)
-            (setq next (line-beginning-position 2))
-            (goto-char start)
-            (setq start (line-beginning-position))
-                  
-            ;; Fontify the chunk, and mark it as fontified.
-            ;; We mark it first, to make sure that we don't indefinitely
-            ;; re-execute this fontification if an error occurs.
-            (add-text-properties start next '(fontified t))
-            (if jit-lock-functions
-                (run-hook-with-args 'jit-lock-functions start next)
-              (font-lock-fontify-region start next))
-                  
-            ;; Find the start of the next chunk, if any.
-            (setq start (text-property-any next end 'fontified nil)))))))))
+     (unless start (setq start (point-min)))
+     (setq end (if end (min end (point-max)) (point-max)))
+     ;; This did bind `font-lock-beginning-of-syntax-function' to
+     ;; nil at some point, for an unknown reason.  Don't do this; it
+     ;; can make highlighting slow due to expensive calls to
+     ;; `parse-partial-sexp' in function
+     ;; `font-lock-fontify-syntactically-region'.  Example: paging
+     ;; from the end of a buffer to its start, can do repeated
+     ;; `parse-partial-sexp' starting from `point-min', which can
+     ;; take a long time in a large buffer.
+     (let (next)
+       (save-match-data
+        ;; Fontify chunks beginning at START.  The end of a
+        ;; chunk is either `end', or the start of a region
+        ;; before `end' that has already been fontified.
+        (while start
+          ;; Determine the end of this chunk.
+          (setq next (or (text-property-any start end 'fontified t)
+                         end))
+
+          ;; Decide which range of text should be fontified.
+          ;; The problem is that START and NEXT may be in the
+          ;; middle of something matched by a font-lock regexp.
+          ;; Until someone has a better idea, let's start
+          ;; at the start of the line containing START and
+          ;; stop at the start of the line following NEXT.
+          (goto-char next)  (setq next (line-beginning-position 2))
+          (goto-char start) (setq start (line-beginning-position))
+            
+          ;; Fontify the chunk, and mark it as fontified.
+          ;; We mark it first, to make sure that we don't indefinitely
+          ;; re-execute this fontification if an error occurs.
+          (put-text-property start next 'fontified t)
+          (run-hook-with-args 'jit-lock-functions start next)
+
+          ;; Find the start of the next chunk, if any.
+          (setq start (text-property-any next end 'fontified nil))))))))
 
 \f
 ;;; Stealth fontification.
@@ -339,7 +345,7 @@ Value is nil if there is nothing more to fontify."
       nil
     (save-restriction
       (widen)
-      (let* ((next (text-property-any around (point-max) 'fontified nil))
+      (let* ((next (text-property-not-all around (point-max) 'fontified t))
             (prev (previous-single-property-change around 'fontified))
             (prop (get-text-property (max (point-min) (1- around))
                                      'fontified))
@@ -349,11 +355,11 @@ Value is nil if there is nothing more to fontify."
                      ;; and the start of the buffer.  If PROP is
                      ;; non-nil, everything in front of AROUND is
                      ;; fontified, otherwise nothing is fontified.
-                     (if prop
+                     (if (eq prop t)
                          nil
                        (max (point-min)
                             (- around (/ jit-lock-chunk-size 2)))))
-                    (prop
+                    ((eq prop t)
                      ;; PREV is the start of a region of fontified
                      ;; text containing AROUND.  Start fontifying a
                      ;; chunk size before the end of the unfontified
@@ -378,6 +384,7 @@ Value is nil if there is nothing more to fontify."
   "Fontify buffers stealthily.
 This functions is called after Emacs has been idle for
 `jit-lock-stealth-time' seconds."
+  ;; I used to check `inhibit-read-only' here, but I can't remember why.  -stef
   (unless (or executing-kbd-macro
              (window-minibuffer-p (selected-window)))
     (let ((buffers (buffer-list))
@@ -413,9 +420,20 @@ This functions is called after Emacs has been idle for
                    (widen)
                    (when (and (>= jit-lock-first-unfontify-pos (point-min))
                               (< jit-lock-first-unfontify-pos (point-max)))
+                     ;; If we're in text that matches a complex multi-line
+                     ;; font-lock pattern, make sure the whole text will be
+                     ;; redisplayed eventually.
+                     (when (get-text-property jit-lock-first-unfontify-pos
+                                              'jit-lock-defer-multiline)
+                       (setq jit-lock-first-unfontify-pos
+                             (or (previous-single-property-change
+                                  jit-lock-first-unfontify-pos
+                                  'jit-lock-defer-multiline)
+                                 (point-min))))
                      (with-buffer-prepared-for-jit-lock
-                      (put-text-property jit-lock-first-unfontify-pos
-                                         (point-max) 'fontified nil))
+                       (remove-text-properties
+                        jit-lock-first-unfontify-pos (point-max)
+                        '(fontified nil jit-lock-defer-multiline nil)))
                      (setq jit-lock-first-unfontify-pos (point-max)))))
 
                ;; In the following code, the `sit-for' calls cause a
@@ -425,24 +443,54 @@ This functions is called after Emacs has been idle for
                ;; an unmodified buffer would show a `*'.
                (let (start
                      (nice (or jit-lock-stealth-nice 0))
-                     (point (point)))
+                     (point (point-min)))
                  (while (and (setq start
                                    (jit-lock-stealth-chunk-start point))
                              (sit-for nice))
                    
+                   ;; fontify a block.
+                   (jit-lock-fontify-now start (+ start jit-lock-chunk-size))
+                   ;; If stealth jit-locking is done backwards, this leads to
+                   ;; excessive O(n^2) refontification.   -stef
+                   ;; (when (>= jit-lock-first-unfontify-pos start)
+                   ;;   (setq jit-lock-first-unfontify-pos end))
+                   
                    ;; Wait a little if load is too high.
                    (when (and jit-lock-stealth-load
                               (> (car (load-average)) jit-lock-stealth-load))
-                     (sit-for (or jit-lock-stealth-time 30)))
-                   
-                   ;; Unless there's input pending now, fontify.
-                   (unless (input-pending-p)
-                     (jit-lock-function-1 start))))))))))))
+                     (sit-for (or jit-lock-stealth-time 30)))))))))))))
 
 
 \f
 ;;; Deferred fontification.
 
+(defun jit-lock-deferred-fontify ()
+  "Fontify what was deferred."
+  (when jit-lock-buffers
+    ;; Mark the deferred regions back to `fontified = nil'
+    (dolist (buffer jit-lock-buffers)
+      (when (buffer-live-p buffer)
+       (with-current-buffer buffer
+         ;; (message "Jit-Defer %s" (buffer-name))
+         (with-buffer-prepared-for-jit-lock
+          (let ((pos (point-min)))
+            (while
+                (progn
+                  (when (eq (get-text-property pos 'fontified) 'defer)
+                    (put-text-property
+                     pos (setq pos (next-single-property-change
+                                    pos 'fontified nil (point-max)))
+                     'fontified nil))
+                  (setq pos (next-single-property-change pos 'fontified)))))))))
+    (setq jit-lock-buffers nil)
+    ;; Force fontification of the visible parts.
+    (let ((jit-lock-defer-time nil))
+      ;; (message "Jit-Defer Now")
+      (sit-for 0)
+      ;; (message "Jit-Defer Done")
+      )))
+      
+
 (defun jit-lock-after-change (start end old-len)
   "Mark the rest of the buffer as not fontified after a change.
 Installed on `after-change-functions'.
@@ -460,6 +508,15 @@ will take place when text is fontified stealthily."
        ;; be inconsistent with the buffer's content.
        (goto-char start)
        (setq start (line-beginning-position))
+       
+       ;; If we're in text that matches a multi-line font-lock pattern,
+       ;; make sure the whole text will be redisplayed.
+       ;; I'm not sure this is ever necessary and/or sufficient.  -stef
+       (when (get-text-property start 'font-lock-multiline)
+        (setq start (or (previous-single-property-change
+                         start 'font-lock-multiline)
+                        (point-min))))
+       
        ;; Make sure we change at least one char (in case of deletions).
        (setq end (min (max end (1+ start)) (point-max)))
        ;; Request refontification.
@@ -471,4 +528,4 @@ will take place when text is fontified stealthily."
   
 (provide 'jit-lock)
 
-;; jit-lock.el ends here
+;;; jit-lock.el ends here