bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Font-lock: Major mode should be able to specify region to fontify.


From: Alan Mackenzie
Subject: Font-lock: Major mode should be able to specify region to fontify.
Date: 10 May 2002 21:31:03 +0200
Date: Fri, 10 May 2002 19:32:11 +0000
User-agent: tin/1.4.5-20010409 ("One More Nightmare") (UNIX) (Linux/2.0.35 (i686))

Currently, when a buffer change occurs, the region which font-lock
refontifies is rigidly constrained to the smallest set of complete lines
which enclose the changed region.  Also, there is an implicit assumption
in font-lock that a buffer change can _never_ cause refontification
earlier in the buffer.  This works well most of the time, but isn't
always satisfactory.  

For example, in awk-mode I want to give an unmatched string/regexp
delimiter font-lock-warning-face.  This works well as long as the string
isn't continued to another line.  In the following,

1 "A string which \
2 straddles \
3 several \
4 lines
       ^
     point.

the " on line 1 currently has warning-face, since it's unmatched.  As
soon as the user types in the closing " on line 4, I want to refontify
the " on line 1 to string-face.  Should any of the \s be deleted, then
_both_ "s would get warning-face, and the tail of the string would lose
the string-face.

To do this requires that awk-mode can tell font-lock to fontify lines 1
to 4, rather than just line 4 which it currently does.

I have implemented this feature in font-lock.el (and friends) by creating
a new abnormal hook variable which, if set, is called by one of the
font-lock after-change functions.  Here is the patch.  The context-diff
is based on the source files from Emacs 21.1.  

;;;;;; Changelog entry
2002-05-10  Alan Mackenzie  <address@hidden>

        The following set of changes allows a major mode dynamically to
        specify the region to fontify after a buffer change. (fast-lock.el
        doesn't need changing.)
        * font-lock.el
        New abnormal hook before-font-lock-after-change-function,
        New function font-lock-run-before-after-change-hook.
        Changed font-lock-after-change-function.
        * jit-lock.el
        Changed jit-lock-after-change
        * lazy-lock.el
        Changed lazy-lock-defer-line-after-change and
        lazy-lock-defer-rest-after-change.
;;;;;; End of Changelog entry

;;;;;; Patch
diff -c -x ChangeLog -x Makefile -x README 
/usr/src/packages/BUILD/emacs-21.1/lisp/font-lock.el NEW/font-lock.el
*** /usr/src/packages/BUILD/emacs-21.1/lisp/font-lock.el        Wed Sep  5 
13:36:29 2001
--- NEW/font-lock.el    Fri May 10 19:24:25 2002
***************
*** 1260,1270 ****
                                '(face nil syntax-table nil font-lock-multiline 
nil)
                              '(face nil font-lock-multiline nil)))))
  
  ;; Called when any modification is made to buffer text.
  (defun font-lock-after-change-function (beg end old-len)
!   (let ((inhibit-point-motion-hooks t))
      (save-excursion
        (save-match-data
        ;; Rescan between start of lines enclosing the region.
        (font-lock-fontify-region
         (progn (goto-char beg) (beginning-of-line) (point))
--- 1260,1309 ----
                                '(face nil syntax-table nil font-lock-multiline 
nil)
                              '(face nil font-lock-multiline nil)))))
  
+ (defvar before-font-lock-after-change-function nil
+   "If set to a function, this can specify the region to fontify after a 
change.
+ 
+ This variable is a buffer-local abnormal hook whose value, if set, should be a
+ single function.  The function gets called from the active font-lock
+ after-change function, and is intended to allow a major mode to calculate for
+ itself the region to be fontified after a buffer change.
+ 
+ The function is given three parameters, the standard BEG, END and OLD-LEN from
+ after-change-functions.  It should return either a cons of the beginning and 
end
+ buffer-positions \(in that order\) of the region to fontify, or nil (in which
+ case the default region will be used).")
+ (make-variable-buffer-local 'before-font-lock-after-change-function)
+ 
+ (defun font-lock-run-before-after-change-hook (beg end old-len)
+   "Run the hook function, if any, in before-font-lock-after-change-function,
+ returning its value (a cons of beg and end), if it's valid, else nil.
+ 
+ BEG END and OLD-LEN are the three parameters supplied by
+ after-change-functions."
+   (cond ((null before-font-lock-after-change-function) nil)
+         ((not (functionp before-font-lock-after-change-function))
+          (message "before-font-lock-after-change-function's value is not a \
+ function in buffer %S"
+                   (buffer-name))
+          nil)
+         (t (let ((region (funcall before-font-lock-after-change-function beg 
end old-len)))
+              (cond ((null region) nil)
+                    ((or (not (consp region))
+                         (not (wholenump (car region))) (not (wholenump (cdr 
region)))
+                         (not (<= (car region) (cdr region))))
+                     (message "before-font-lock-after-change-function returned 
%S.  \
+ This isn't a cons \(beg.end\), with beg and end numbers, and beg <= end")
+                     nil)
+                    (t region))))))
+ 
  ;; Called when any modification is made to buffer text.
  (defun font-lock-after-change-function (beg end old-len)
!   (let ((inhibit-point-motion-hooks t) region)
      (save-excursion
        (save-match-data
+         ;; Does the major mode have its own ideas about the region to fontify?
+         (setq region (font-lock-run-before-after-change-hook beg end old-len))
+         (if region (setq beg (car region)  end (cdr region)))
        ;; Rescan between start of lines enclosing the region.
        (font-lock-fontify-region
         (progn (goto-char beg) (beginning-of-line) (point))
diff -c -x ChangeLog -x Makefile -x README 
/usr/src/packages/BUILD/emacs-21.1/lisp/jit-lock.el NEW/jit-lock.el
*** /usr/src/packages/BUILD/emacs-21.1/lisp/jit-lock.el Mon Jul 16 12:22:58 2001
--- NEW/jit-lock.el     Fri May 10 18:59:36 2002
***************
*** 426,431 ****
--- 426,434 ----
    (when jit-lock-mode
      (save-excursion
        (with-buffer-prepared-for-jit-lock
+        ;; Does the major mode have its own ideas about the region to fontify?
+        (let ((region (font-lock-run-before-after-change-hook start end 
old-len)))
+          (if region (setq start (car region)  end (cdr region))))
         ;; It's important that the `fontified' property be set from the
         ;; beginning of the line, else font-lock will properly change the
         ;; text's face, but the display will have been done already and will
diff -c -x ChangeLog -x Makefile -x README 
/usr/src/packages/BUILD/emacs-21.1/lisp/lazy-lock.el NEW/lazy-lock.el
*** /usr/src/packages/BUILD/emacs-21.1/lisp/lazy-lock.el        Thu Aug 16 
14:25:15 2001
--- NEW/lazy-lock.el    Fri May 10 19:00:47 2002
***************
*** 771,776 ****
--- 771,779 ----
    (save-buffer-state nil
      (unless (memq (current-buffer) lazy-lock-buffers)
        (push (current-buffer) lazy-lock-buffers))
+     ;; Does the major mode have its own ideas about what to fontify?
+     (let ((region (font-lock-run-before-after-change-hook beg end old-len)))
+       (if region (setq beg (car region)  end (cdr region))))
      (remove-text-properties (max (1- beg) (point-min))
                            (min (1+ end) (point-max))
                            '(lazy-lock nil))))
***************
*** 784,789 ****
--- 787,795 ----
        (push (current-buffer) lazy-lock-buffers))
      (save-restriction
        (widen)
+       ;; Does the major mode have its own ideas about what to fontify?
+       (let ((region (font-lock-run-before-after-change-hook beg end old-len)))
+         (if region (setq beg (car region)  end (cdr region))))
        (remove-text-properties (max (1- beg) (point-min))
                              (point-max)
                              '(lazy-lock nil)))))
;;;;;; end of patch.

-- 
Alan Mackenzie (Munich, Germany)
Email: address@hidden; to decode, wherever there is a repeated letter
(like "aa"), remove half of them (leaving, say, "a").




reply via email to

[Prev in Thread] Current Thread [Next in Thread]