changeset 72251:0933613f837b

(font-lock-beg, font-lock-end, font-lock-extend-region-functions): New vars. (font-lock-extend-region-multiline) (font-lock-extend-region-wholelines): New functions. (font-lock-default-fontify-region): Use them. (font-lock-extend-jit-lock-region-after-change): Only round up if font-lock-default-fontify-region will do it as well.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Thu, 03 Aug 2006 07:14:39 +0000
parents 482bf4e8cc00
children 54e1bf749744
files etc/NEWS lisp/ChangeLog lisp/font-lock.el lispref/modes.texi
diffstat 4 files changed, 88 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS	Thu Aug 03 05:42:53 2006 +0000
+++ b/etc/NEWS	Thu Aug 03 07:14:39 2006 +0000
@@ -5363,6 +5363,11 @@
 property over the second half of the command to force (deferred)
 refontification of `bar' whenever the `e' is added/removed.
 
+*** `font-lock-extend-region-functions' makes it possible to alter the way
+the fontification region is chosen.  This can be used to prevent rounding
+up to whole lines, or to extend the region to include all related lines
+of multiline constructs so that such constructs get properly recognized.
+
 ** Major mode mechanism changes:
 
 +++
--- a/lisp/ChangeLog	Thu Aug 03 05:42:53 2006 +0000
+++ b/lisp/ChangeLog	Thu Aug 03 07:14:39 2006 +0000
@@ -1,5 +1,13 @@
 2006-08-03  Stefan Monnier  <monnier@iro.umontreal.ca>
 
+	* font-lock.el (font-lock-beg, font-lock-end)
+	(font-lock-extend-region-functions): New vars.
+	(font-lock-extend-region-multiline)
+	(font-lock-extend-region-wholelines): New functions.
+	(font-lock-default-fontify-region): Use them.
+	(font-lock-extend-jit-lock-region-after-change): Only round up
+	if font-lock-default-fontify-region will do it as well.
+
 	* font-lock.el (font-lock-extend-after-change-region-function):
 	Rename from font-lock-extend-region-function.
 	(font-lock-extend-region): Remove by inlining at call sites.
--- a/lisp/font-lock.el	Thu Aug 03 05:42:53 2006 +0000
+++ b/lisp/font-lock.el	Thu Aug 03 07:14:39 2006 +0000
@@ -1040,6 +1040,53 @@
 Useful for things like RMAIL and Info where the whole buffer is not
 a very meaningful entity to highlight.")
 
+
+(defvar font-lock-beg) (defvar font-lock-end)
+(defvar font-lock-extend-region-functions
+  '(font-lock-extend-region-wholelines
+    font-lock-extend-region-multiline)
+  "Special hook run just before proceeding to fontify a region.
+This is used to allow major modes to help font-lock find safe buffer positions
+as beginning and end of the fontified region.  Its most common use is to solve
+the problem of /identification/ of multiline elements by providing a function
+that tries to find such elements and move the boundaries such that they do
+not fall in the middle of one.
+Each function is called with no argument; it is expected to adjust the
+dynamically bound variables `font-lock-beg' and `font-lock-end'; and return
+non-nil iff it did make such an adjustment.
+These functions are run in turn repeatedly until they all return nil.
+Put first the functions more likely to cause a change and cheaper to compute.")
+;; Mark it as a special hook which doesn't use any global setting
+;; (i.e. doesn't obey the element t in the buffer-local value).
+(make-variable-buffer-local 'font-lock-extend-region-functions)
+
+(defun font-lock-extend-region-multiline ()
+  "Move fontification boundaries away from any `font-lock-multiline' property."
+  (let ((changed nil))
+    (when (and (> font-lock-beg (point-min))
+               (get-text-property (1- font-lock-beg) 'font-lock-multiline))
+      (setq changed t)
+      (setq font-lock-beg (or (previous-single-property-change
+                               font-lock-beg 'font-lock-multiline)
+                              (point-min))))
+    ;; 
+    (when (get-text-property font-lock-end 'font-lock-multiline)
+      (setq changed t)
+      (setq font-lock-end (or (text-property-any font-lock-end (point-max)
+                                                 'font-lock-multiline nil)
+                              (point-max))))
+    changed))
+  
+  
+(defun font-lock-extend-region-wholelines ()
+  "Move fontification boundaries to beginning of lines."
+  (let ((changed nil))
+    (goto-char font-lock-beg)
+    (unless (bobp) (setq changed t font-lock-beg (line-beginning-position)))
+    (goto-char font-lock-end)
+    (unless (bobp) (setq changed t font-lock-end (line-beginning-position 2)))
+    changed))
+
 (defun font-lock-default-fontify-region (beg end loudly)
   (save-buffer-state
       ((parse-sexp-lookup-properties
@@ -1051,24 +1098,21 @@
 	  ;; Use the fontification syntax table, if any.
 	  (when font-lock-syntax-table
 	    (set-syntax-table font-lock-syntax-table))
-          (goto-char beg)
-	  (setq beg (line-beginning-position))
-	  ;; check to see if we should expand the beg/end area for
-	  ;; proper multiline matches
-	  (when (and (> beg (point-min))
-		     (get-text-property (1- beg) 'font-lock-multiline))
-	    ;; We are just after or in a multiline match.
-	    (setq beg (or (previous-single-property-change
-			   beg 'font-lock-multiline)
-			  (point-min)))
-	    (goto-char beg)
-	    (setq beg (line-beginning-position)))
-          (setq end (or (text-property-any end (point-max)
-                                           'font-lock-multiline nil)
-                        (point-max)))
-	  (goto-char end)
-	  ;; Round up to a whole line.
-          (unless (bolp) (setq end (line-beginning-position 2)))
+          ;; Extend the region to fontify so that it starts and ends at
+          ;; safe places.
+          (let ((funs font-lock-extend-region-functions)
+                (font-lock-beg beg)
+                (font-lock-end end))
+            (while funs
+              (setq funs (if (or (not (funcall (car funs)))
+                                 (eq funs font-lock-extend-region-functions))
+                             (cdr funs)
+                           ;; If there's been a change, we should go through
+                           ;; the list again since this new position may
+                           ;; warrant a different answer from one of the fun
+                           ;; we've already seen.
+                           font-lock-extend-region-functions)))
+            (setq beg font-lock-beg end font-lock-end))
 	  ;; Now do the fontification.
 	  (font-lock-unfontify-region beg end)
 	  (when font-lock-syntactic-keywords
@@ -1144,12 +1188,14 @@
       ;; Finally, pre-enlarge the region to a whole number of lines, to try
       ;; and predict what font-lock-default-fontify-region will do, so as to
       ;; avoid double-redisplay.
-      (goto-char beg)
-      (forward-line 0)
-      (setq jit-lock-start (min jit-lock-start (point)))
-      (goto-char end)
-      (forward-line 1)
-      (setq jit-lock-end (max jit-lock-end (point))))))
+      (when (memq 'font-lock-extend-region-wholelines
+                  font-lock-extend-region-functions)
+        (goto-char beg)
+        (forward-line 0)
+        (setq jit-lock-start (min jit-lock-start (point)))
+        (goto-char end)
+        (forward-line 1)
+        (setq jit-lock-end (max jit-lock-end (point)))))))
 
 (defun font-lock-fontify-block (&optional arg)
   "Fontify some lines the way `font-lock-fontify-buffer' would.
--- a/lispref/modes.texi	Thu Aug 03 05:42:53 2006 +0000
+++ b/lispref/modes.texi	Thu Aug 03 07:14:39 2006 +0000
@@ -3044,7 +3044,7 @@
 make the other also work.  However, for reliable results you must
 attend explicitly to both aspects.
 
-  There are two ways to ensure correct identification of multiline
+  There are three ways to ensure correct identification of multiline
 constructs:
 
 @itemize
@@ -3055,6 +3055,10 @@
 Use @code{font-lock-fontify-region-function} hook to extend the scan
 so that the scanned text never starts or ends in the middle of a
 multiline construct.
+@item
+Add a function to @code{font-lock-extend-region-functions} that does
+the \emph{identification} and extends the scan so that the scanned
+text never starts or ends in the middle of a multiline construct.
 @end itemize
 
   There are three ways to do rehighlighting of multiline constructs: