Mercurial > hg > xemacs-beta
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/packages/lazy-lock.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,1102 @@ +;;; lazy-lock.el --- Lazy demand-driven fontification for fast Font Lock mode. + +;; Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +;; Author: Simon Marshall <simon@gnu.ai.mit.edu> +;; Keywords: faces files +;; Version: 1.14 + +;; LCD Archive Entry: +;; lazy-lock|Simon Marshall|simon@gnu.ai.mit.edu| +;; Lazy Font Lock mode (with fast demand-driven fontification).| +;; 13-Oct-95|1.14|~/modes/lazy-lock.el.Z| + +;; The archive is archive.cis.ohio-state.edu in /pub/gnu/emacs/elisp-archive. + +;;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Synched up with: Not in FSF. (This seems very strange to me.) + +;;; Commentary: + +;; Purpose: +;; +;; To make visiting buffers in `font-lock-mode' faster by making fontification +;; be demand-driven and stealthy. +;; Fontification only occurs when, and where, necessary. +;; +;; See caveats and feedback below. See also the defer-lock and fast-lock +;; packages. (But don't use lazy-lock.el and fast-lock.el at the same time!) + +;; Installation: +;; +;; Put this file somewhere where Emacs can find it (i.e., in one of the paths +;; in your `load-path'), `byte-compile-file' it, and put in your ~/.emacs: +;; +;; (autoload 'turn-on-lazy-lock "lazy-lock" +;; "Unconditionally turn on Lazy Lock mode.") +;; +;; (add-hook 'font-lock-mode-hook 'turn-on-lazy-lock) +;; +;; Start up a new Emacs and use font-lock as usual (except that you can use the +;; so-called "gaudier" fontification regexps on big files without frustration). +;; +;; In a buffer (which has `font-lock-mode' enabled) which is at least +;; `lazy-lock-minimum-size' characters long, only the visible portion of the +;; buffer will be fontified. Motion around the buffer will fontify those +;; visible portions that were not previous fontified. If the variable +;; `lazy-lock-hide-invisible' is non-nil, redisplay will be delayed until after +;; fontification. Otherwise, text that has not yet been fontified is displayed +;; in `lazy-lock-invisible-foreground'. +;; +;; If stealth fontification is enabled, fontification will occur in invisible +;; parts of the buffer after `lazy-lock-stealth-time' seconds of idle time. + +;; Advanced Use: +;; +;; You can also do fancy things with `advice'. For example, to fontify when +;; dragging the scroll-bar in Emacs, you could put in your ~/.emacs: +;; +;; (autoload 'lazy-lock-post-command-fontify-windows "lazy-lock") +;; +;; (defadvice scroll-bar-drag-1 (after fontify-window activate compile) +;; (let ((lazy-lock-walk-windows nil) (lazy-lock-hide-invisible nil)) +;; (lazy-lock-post-command-fontify-windows))) +;; +;; Or to fontify when the Debugger pops up a source code window: +;; +;; (autoload 'lazy-lock-fontify-walk-windows "lazy-lock") +;; +;; (defadvice gud-display-line (after fontify-window activate compile) +;; (let ((lazy-lock-walk-windows t) (lazy-lock-hide-invisible t)) +;; (lazy-lock-fontify-walk-windows))) +;; +;; Scott Byer <byer@mv.us.adobe.com> suggested this to fontify the visible part +;; of an insertion only: +;; +;; (defvar lazy-lock-insert-commands +;; '(yank yank-pop clipboard-yank hilit-yank hilit-yank-pop +;; mail-yank-original mouse-yank-at-click mouse-yank-secondary +;; yank-rectangle) +;; "A list of insertion commands.") +;; +;; (defadvice font-lock-after-change-function (around fontify-insertion +;; activate compile) +;; (if (or (not (memq this-command lazy-lock-insert-commands)) +;; (and (pos-visible-in-window-p beg) (pos-visible-in-window-p end))) +;; ad-do-it +;; (let ((this-command 'ignore)) +;; (put-text-property beg end 'fontified nil) +;; (lazy-lock-fontify-window)))) +;; +;; Let me know if you use any other `advice' and I'll put it here. Thanks. +;; +;; These kinds of things with `advice' aren't done automatically because they +;; cause large packages (advice.el plus bytecomp.el and friends) to be loaded. + +;; Caveats: +;; +;; Lazy Lock mode does not work efficiently with Outline mode. This is because +;; when in Outline mode, although text may be hidden (not visible in the +;; window), the text is visible to Emacs Lisp code (not surprisingly) and Lazy +;; Lock fontifies it mercilessly. Hopefully this will be fixed one day. +;; +;; Lazy Lock mode does not fontify windows as they appear: +;; +;; 1. With `query-replace' or `ispell-*', as Lazy Lock only knows about point +;; motion after the command exits. +;; +;; 2. When displayed by gud.el (the Grand Unified Debugger), as they are +;; displayed via a process sentinel. See `Advanced Use' above. +;; +;; 3. In XEmacs 19.12, when the last command was invoked via a mouse event, +;; because of a bug/feature in/of `sit-for'. +;; +;; 4. In other random situations that I don't know about (yet). +;; +;; If you have `lazy-lock-hide-invisible' you may notice that redisplay occurs +;; before fontification regardlessly. This is due to other packages sitting on +;; `post-command-hook' and provoking redisplay. If you use these packages, you +;; can't use `lazy-lock-hide-invisible'. +;; +;; If you have `lazy-lock-hide-invisible' and use scrollbar scrolling using +;; Emacs 19, hidden text will not be fontified as it becomes visible. It is +;; expected that Emacs 19 will provide the necessary hooks in future, to solve +;; this problem and the problem above. +;; +;; Unless otherwise stated, "Emacs 19.X" means versions up to and including X. +;; +;; In Emacs 19.25, one `window-start'/`window-end' bug means that if you open a +;; file in another frame (such as via `find-tag-other-frame'), the whole buffer +;; is fontified regardless. Upgrade! +;; +;; In Emacs 19.25, fontification by stealth is turned off because of a fatal +;; bug in `previous-single-property-change'. Upgrade! +;; +;; In Emacs 19.28, if you see a message in the minibuffer of the form +;; "Fontifying window... done. (Restarted in foo.c)" +;; it means the Garbage Collector has marked some (subsequently used) text +;; properties. Lazy Lock attempts to recover the situation by restarting in +;; that buffer. Unfortunately, that buffer will be left in a writable and +;; modified state. Also, other windows may not be fontified when this happens. +;; To reduce the frequency of this bug occuring, increase in your ~/.emacs the +;; value of `gc-cons-threshold' to, say, 1Meg, e.g.: +;; +;; (setq gc-cons-threshold (* 1024 1024)) +;; +;; The solution is to upgrade! (With thanks to Kevin Broadey for help here.) +;; +;; For XEmacs 19.11 and Lucid Emacs 19.10 users, lazy-lock sort-of works. +;; There are bugs in text property and point/window primatives. Upgrade! + +;; Feedback: +;; +;; Feedback is welcome. +;; To submit a bug report (or make comments) please use the mechanism provided: +;; +;; M-x lazy-lock-submit-bug-report RET + +;; History: +;; +;; 0.01--1.00: +;; - Changed name from fore-lock to lazy-lock. Shame though. +;; - Dropped `advice'-wrapping completely. Ask me if you're interested in it. +;; - Made `lazy-lock-mode' ignore `post-command-hook' and `buffer-file-name'. +;; - Made `lazy-lock-fontify-window' check `lazy-lock-mode' and `this-command'. +;; - Made `lazy-lock-fontify-window' redisplay via `sit-for'. +;; - Added `lazy-lock-minimum-size' to control `lazy-lock-mode'. +;; 1.00--1.01: +;; - Added `lazy-lock-fontify-buffer'. +;; - Made `lazy-lock-fontify-window' ignore `lazy-lock-mode'. +;; - Made `lazy-lock-fontify-window' suspicious of `window-' favourites again. +;; - Added `lazy-lock-delay-commands' (idea from William G. Dubuque). +;; - Added `lazy-lock-ignore-commands' for completeness. +;; - Added `lazy-lock-continuity-time' for normal input delay. +;; 1.01--1.02: +;; - Made `lazy-lock-fontify-window' cope with multiple unfontified regions. +;; - Made `lazy-lock-mode' remove `fontified' properties if turned off. +;; - Made `lazy-lock-fontify-window' fontify by lines. +;; - Added `lazy-lock-cache-position' buffer local to detect visibility change. +;; - Added `lazy-lock-post-command-hook' to do the waiting. +;; - Made `lazy-lock-fontify-window' just do the fontification. +;; - Made `lazy-lock-mode' append `lazy-lock-post-command-hook'. +;; - Added `lazy-lock-walk-windows' to hack multi-window motion. +;; - Made `lazy-lock-post-command-hook' `walk-windows' if variable is non-nil. +;; - Removed `lazy-lock-ignore-commands' since insertion may change window. +;; - Added `lazy-lock-fontify-stealthily' and `lazy-lock-stealth-time'. +;; - Made `lazy-lock-post-command-hook' use them. +;; 1.02--1.03: +;; - Made `lazy-lock-fontify-stealthily' do `forward-line' not `previous-line'. +;; - Made `lazy-lock-fontify-stealthily' `move-to-window-line' first. +;; - Made `lazy-lock-fontify-stealthily' use `text-property-any' for region. +;; - Made `lazy-lock-post-command-hook' loop on `lazy-lock-fontify-stealthily'. +;; 1.03--1.04: +;; - Made `lazy-lock-mode' reset `lazy-lock-cache-position'. +;; - Made `lazy-lock-post-command-hook' `widen' for `if' `text-property-any'. +;; - Made `lazy-lock-fontify-stealthily' return `text-property-any'. +;; - Added `lazy-lock-percent-fontified' for a/be-musement. +;; - Made `lazy-lock-post-command-hook' use it. +;; - Made `lazy-lock-mode' use `make-local-hook' etc. if available. +;; - Made `lazy-lock-mode' use `before-revert-hook' and `after-revert-hook'. +;; - Made `lazy-lock-post-command-hook' protect `deactivate-mark'. +;; - Adds `lazy-lock-post-command-hook' globally to `post-command-hook'. +;; 1.04--1.05: +;; - Made `lazy-lock-mode' test `make-local-hook' not `emacs-minor-version'. +;; 1.05--1.06: +;; - Added `lazy-lock-ignore-commands' for commands that leave no event but do. +;; - Made `lazy-lock-post-command-hook' check `lazy-lock-ignore-commands'. +;; 1.06--1.07: +;; - Removed `before-revert-hook' and `after-revert-hook' use. +;; 1.07--1.08: +;; - Added `lazy-lock-submit-bug-report'. +;; - Made `lazy-lock-post-command-hook' check `executing-macro'. +;; - Made it sort-of/almost work for XEmacs (help from Jonas Jarnestrom). +;; - XEmacs: Fix `text-property-not-all' (fix based on fast-lock.el 3.05 fix). +;; - XEmacs: Set `font-lock-no-comments' and alias `frame-parameters'. +;; - Made `byte-compile-warnings' omit `unresolved' on compilation. +;; - Made `lazy-lock-post-command-hook' protect `buffer-undo-list'. +;; - Moved `deactivate-mark' and `buffer-undo-list' protection to functions. +;; - Added `lazy-lock-invisible-foreground' (idea from Boris Goldowsky). +;; - XEmacs: Fix to use `text-property-not-all' t, not `text-property-any' nil. +;; - Made `lazy-lock-percent-fontified' return `round' to an integer. +;; - XEmacs: Fix `text-property-any' (fix and work around for a bug elsewhere). +;; - XEmacs: Fix `lazy-lock-submit-bug-report' for reporter.el & vm-window.el. +;; - XEmacs: Made `lazy-lock-fontify-window' loop `while' `<' not `/='. +;; - Use `font-lock-after-change-function' to do the fontification. +;; 1.08--1.09: +;; - Made `lazy-lock-post-command-hook' protect with `condition-case'. +;; - Made `lazy-lock-cache-start' to cache `window-start'. +;; - Made `lazy-lock-fontify-window' check and cache `lazy-lock-cache-start'. +;; - Renamed `lazy-lock-cache-position' to `lazy-lock-cache-end'. +;; - XEmacs: Fix for `font-lock-after-change-function'. +;; - Adds `lazy-lock-post-command-hook' globally to `window-setup-hook'. +;; 1.09--1.10: +;; - Made `buffer-file-name' be `let' to prevent supersession (Kevin Broadey). +;; - Made `lazy-lock-submit-bug-report' `require' reporter (Ilya Zakharevich). +;; - Made `lazy-lock-mode' and `turn-on-lazy-lock' succeed `autoload' cookies. +;; - Added `lazy-lock-fontify-walk-windows' for walking window fontification. +;; - Added `lazy-lock-fontify-walk-stealthily' for walking stealth. +;; - Removed `move-to-window-line' from `lazy-lock-fontify-stealthily'. +;; - Made `lazy-lock-percent-fontified' use `truncate' rather than `round'. +;; - Added other `*-argument' to `lazy-lock-ignore-commands' (Kevin Broadey). +;; - Made `lazy-lock-fontify-stealthily' not assume buffer is part `fontified'. +;; - Emacs: Fix for `font-lock-fontify-region'. +;; - Made `lazy-lock-post-command-hook' check for minibuffer (Kevin Broadey). +;; - Added `lazy-lock-stealth-nice' for niceness during stealth fontification. +;; - Added `lazy-lock-stealth-lines' for chunks of stealth fontification. +;; 1.10--1.11: incorporated hack by Ben Wing from William Dubuque's fontifly.el +;; - Made `lazy-lock-fontify-stealthily' see a non `fontified' preceding line. +;; - XEmacs: Fix `text-property-any' and `text-property-not-all' (Ben Wing). +;; - XEmacs: Fix `lazy-lock-continuity-time' (Ben Wing). +;; - Added awful `lazy-lock-running-xemacs-p' (Ben Wing). +;; - Made loading set `emacs-minor-version' if it's not bound. +;; - Added `lazy-lock-hide-invisible' to control redisplay. +;; - Made `lazy-lock-post-command-hook' use it in `sit-for' (Ben Wing). +;; - Made `lazy-lock-fontify-window' move relative to `end-of-line' if non-nil. +;; - Added `lazy-lock-fontify-region' so packages can ensure fontification. +;; - Made `lazy-lock-fontify-walk-stealthily' do stealth widening. +;; - Made `lazy-lock-fontify-stealthily' always do adjacent preceding regions. +;; - Added `lazy-lock-after-fontify-buffer'. +;; - XEmacs: Removed `font-lock-no-comments' incompatibility code. +;; - Removed `lazy-lock-delay-time' and `lazy-lock-delay-commands'. +;; - Removed `lazy-lock-post-command' and split the functionality. +;; - Adds `lazy-lock-post-command-fontify-windows' on first. +;; - Adds `lazy-lock-post-command-fontify-stealthily' on last. +;; - Made `lazy-lock-mode' ensure both first and last on `post-command-hook'. +;; - Made `lazy-lock-mode' ensure `font-lock-mode' is on. +;; - Wrap `lazy-lock-post-command-fontify-stealthily' for errors (David Karr). +;; - Added `calcDigit-key' to `lazy-lock-ignore-commands' (Bob Glickstein). +;; - Wrap `lazy-lock-running-xemacs-p' with `eval-and-compile' (Erik Naggum). +;; - XEmacs: Fix use of `previous-single-property-change' (Jim Thompson). +;; - XEmacs: Fix `next-single-property-change' fix for 19.11 (Jim Thompson). +;; - Added `lazy-lock-post-resize-fontify-windows' to fontify on resizing. +;; - Adds globally to `window-size-change-functions'. +;; - Added `lazy-lock-post-setup-fontify-windows' to fontify after start up. +;; - Adds globally to `window-setup-hook'. +;; - Made `lazy-lock-post-command-fontify-windows' check for `input-pending-p'. +;; - Made `save-selected-window' to restore the `selected-window'. +;; - Use `save-selected-window' rather than `save-window-excursion'. +;; 1.11--1.12: +;; - Made `lazy-lock-post-command-fontify-windows' do `set-buffer' first. +;; - Made `lazy-lock-fontify-stealthily' respect narrowing before point. +;; - Added `lazy-lock-post-setup-ediff-control-frame' for Ediff control frame. +;; - Adds globally to `ediff-after-setup-control-frame-hooks'. +;; - Wrap `save-selected-window' with `save-excursion' for `current-buffer'. +;; 1.12--1.13: +;; - XEmacs: Add `lazy-lock-after-fontify-buffer' to the Font Lock hook. +;; - Made `buffer-file-truename' also wrapped for supersession (Rick Sladkey). +;; - Made `font-lock-beginning-of-syntax-function' wrapped for fontification. +;; - Added `lazy-lock-stealth-verbose' (after harassment from Ben Wing). +;; - XEmacs: Made `font-lock-verbose' wrapped for stealth fontification. +;; 1.13--1.14: +;; - Wrap `lazy-lock-colour-invisible' for `set-face-foreground' (Jari Aalto). + +(require 'font-lock) + +(eval-when-compile + ;; Only `require' so `ediff-multiframe-setup-p' is expanded at compile time. + (condition-case nil (require 'ediff) (file-error)) + ;; Well, shouldn't Lazy Lock be as lazy as possible? + ;(setq byte-compile-dynamic t byte-compile-dynamic-docstrings t) + ;; Shut Emacs' byte-compiler up (cf. stop me getting mail from users). + (setq byte-compile-warnings '(free-vars callargs redefine))) + +(defun lazy-lock-submit-bug-report () + "Submit via mail a bug report on lazy-lock.el." + (interactive) + (require 'reporter) + (let ((reporter-prompt-for-summary-p t)) + (reporter-submit-bug-report "simon@gnu.ai.mit.edu" "lazy-lock 1.14" + '(lazy-lock-walk-windows lazy-lock-continuity-time + lazy-lock-stealth-time lazy-lock-stealth-nice + lazy-lock-stealth-lines lazy-lock-stealth-verbose + lazy-lock-hide-invisible lazy-lock-invisible-foreground + lazy-lock-minimum-size lazy-lock-ignore-commands) + nil nil + (concat "Hi Si., + +I want to report a bug. I've read the `Bugs' section of `Info' on Emacs, so I +know how to make a clear and unambiguous report. To reproduce the bug: + +Start a fresh Emacs via `" invocation-name " -no-init-file -no-site-file'. +In the `*scratch*' buffer, evaluate:")))) + +;; Let's define `emacs-major-version', `emacs-minor-version', and +;; `emacs-version>=' if no-one else has. + +(if (not (boundp 'emacs-major-version)) + (eval-and-compile + (defconst emacs-major-version + (progn (or (string-match "^[0-9]+" emacs-version) + (error "emacs-version unparsable")) + (string-to-int (match-string 0 emacs-version))) + "Major version number of this version of Emacs, as an integer. +Warning, this variable did not exist in Emacs versions earlier than: + FSF Emacs: 19.23 + XEmacs: 19.10"))) + +(if (not (boundp 'emacs-minor-version)) + (eval-and-compile + (defconst emacs-minor-version + (progn (or (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version) + (error "emacs-version unparsable")) + (string-to-int (match-string 1 emacs-version))) + "Minor version number of this version of Emacs, as an integer. +Warning, this variable did not exist in Emacs versions earlier than: + FSF Emacs: 19.23 + XEmacs: 19.10"))) + +(if (not (fboundp 'emacs-version>=)) + (eval-and-compile + (defun emacs-version>= (major &optional minor) + "Return true if the Emacs version is >= to the given MAJOR and MINOR numbers. + +The MAJOR version number argument is required, but the MINOR version number +argument is optional. If the minor version number is not specified (or is the +symbol `nil') then only the major version numbers are considered in the test." + (if (null minor) + (>= emacs-major-version major) + (or (> emacs-major-version major) + (and (= emacs-major-version major) + (>= emacs-minor-version minor)) + ) + )))) + +;; Yuck, but we make so much use of this variable it's probably worth it. +(eval-and-compile + (defconst lazy-lock-running-xemacs-p + (not (null (save-match-data (string-match "Lucid" emacs-version)))))) + +(defvar lazy-lock-cache-start nil) ; for window fontifiction +(defvar lazy-lock-cache-end nil) ; for window fontifiction +(defvar lazy-lock-cache-continue nil) ; for stealth fontifiction + +;;;###autoload +(defvar lazy-lock-mode nil) ; for modeline + +;; User Variables: + +(defvar lazy-lock-minimum-size (* 25 1024) + "*If non-nil, the minimum size for buffers. +Only buffers more than this can have demand-driven fontification. +If nil, means size is irrelevant.") + +(defvar lazy-lock-walk-windows t + "*If non-nil, fontify windows other than the selected window. +If `all-frames', fontify windows even on other frames. +A non-nil value slows down redisplay.") + +;; XEmacs 19.11 and below exercise a bug in the Xt event loop. +(defvar lazy-lock-continuity-time + (if (or (not lazy-lock-running-xemacs-p) (emacs-version>= 19 12)) + 0 + (if (featurep 'lisp-float-type) 0.001 1)) + "*Time in seconds to delay before normal window fontification. +Window fontification occurs if there is no input within this time.") + +;; `previous-single-property-change' at `point-min' up to Emacs 19.25 is fatal. +;; `text-property-any', `text-property-not-all' and +;; `next-single-property-change' up to XEmacs 19.11 are too broke. +(defvar lazy-lock-stealth-time + (if (emacs-version>= 19 (if lazy-lock-running-xemacs-p 12 26)) 30) + "*Time in seconds to delay before beginning stealth fontification. +Stealth fontification occurs if there is no input within this time. +If nil, means no fontification by stealth.") + +(defvar lazy-lock-stealth-lines + (cond ((boundp 'font-lock-maximum-decoration) + (if font-lock-maximum-decoration 75 150)) + ((boundp 'font-lock-use-maximal-decoration) + (if font-lock-use-maximal-decoration 50 100)) + (t + 50)) + "*If non-nil, the maximum size of a chunk of stealth fontification. +Each iteration of stealth fontification can fontify this number of lines. +To speed up input response during stealth fontification, at the cost of stealth +taking longer to fontify, you could reduce the value of this variable. +If nil, means use `window-height' for the maximum chunk size.") + +(defvar lazy-lock-stealth-nice (if (featurep 'lisp-float-type) 0.125 1) + "*Time in seconds to pause during chunks of stealth fontification. +To reduce machine load during stealth fontification, at the cost of stealth +taking longer to fontify, you could increase the value of this variable.") + +(defvar lazy-lock-stealth-verbose font-lock-verbose + "*If non-nil, means stealth fontification should show status messages.") + +(defvar lazy-lock-ignore-commands + (append + ;; Standard commands... + '(universal-argument digit-argument negative-argument + isearch-other-control-char isearch-other-meta-char) + ;; And some resulting from non-standard packages... + (if (fboundp 'calc) '(calcDigit-key))) + "A list of commands after which fontification should not occur. +To speed up typing response, at the cost of Lazy Lock not fontifying when +insertion causes scrolling, you could add `self-insert-command' to this list.") + +(defvar lazy-lock-hide-invisible lazy-lock-running-xemacs-p + "*If non-nil, hide invisible text while it is fontified. +If non-nil, redisplay is delayed until after fontification occurs. If nil, +text is shown (in `lazy-lock-invisible-foreground') while it is fontified. +A non-nil value slows down redisplay and can slow down cursor motion.") + +(defvar lazy-lock-invisible-foreground "gray50" + "The foreground colour to use to display invisible text. +If nil, the default foreground is used. If t, the default background is used. +If a string, it should be a colour to use (either its name or its RGB value). +Invisible text is momentarily seen (if `lazy-lock-hide-invisible' is nil) when +scrolling into unfontified regions.") + +;; User Functions: + +;;;###autoload +(defun lazy-lock-mode (&optional arg) + "Toggle Lazy Lock mode. +With arg, turn Lazy Lock mode on if and only if arg is positive and the buffer +is at least `lazy-lock-minimum-size' characters long. + +When Lazy Lock mode is enabled, fontification is demand-driven and stealthy: + + - Fontification occurs in visible parts of buffers when necessary. + Occurs if there is no input after pausing for `lazy-lock-continuity-time'. + + - Fontification occurs in invisible parts when Emacs has been idle. + Occurs if there is no input after pausing for `lazy-lock-stealth-time'. + +If `lazy-lock-hide-invisible' is non-nil, text is not displayed until it is +fontified, otherwise it is displayed in `lazy-lock-invisible-foreground'. + +See also variables `lazy-lock-walk-windows' and `lazy-lock-ignore-commands' for +window (scroll) fontification, and `lazy-lock-stealth-lines', +`lazy-lock-stealth-nice' and `lazy-lock-stealth-verbose' for stealth +fontification. + +Use \\[lazy-lock-submit-bug-report] to send bug reports or feedback." + (interactive "P") + (set (make-local-variable 'lazy-lock-mode) + (and (<= (or lazy-lock-minimum-size 0) (buffer-size)) + (if arg (> (prefix-numeric-value arg) 0) (not lazy-lock-mode)))) + (if (and lazy-lock-mode (not font-lock-mode)) + ;; Turned on `lazy-lock-mode' rather than using `font-lock-mode-hook'. + (progn + (add-hook 'font-lock-mode-hook 'turn-on-lazy-lock) + (font-lock-mode 1)) + (lazy-lock-fixup-hooks) + ;; Let's get down to business. + (if (not lazy-lock-mode) + (let ((modified (buffer-modified-p)) (inhibit-read-only t) + (buffer-undo-list t) + deactivate-mark buffer-file-name buffer-file-truename) + (remove-text-properties (point-min) (point-max) '(fontified nil)) + (or modified (set-buffer-modified-p nil))) + (if (and (not lazy-lock-hide-invisible) lazy-lock-invisible-foreground) + (lazy-lock-colour-invisible)) + (set (make-local-variable 'lazy-lock-cache-start) 0) + (set (make-local-variable 'lazy-lock-cache-end) 0) + (set (make-local-variable 'font-lock-fontified) t)))) + +;;;###autoload +(defun turn-on-lazy-lock () + "Unconditionally turn on Lazy Lock mode." + (lazy-lock-mode 1)) + +(if (not (emacs-version>= 19 (if lazy-lock-running-xemacs-p 12 29))) + ;; We don't need this in Emacs 19.29 or XEmacs 19.12. + (defun lazy-lock-fontify-buffer () + "Fontify the current buffer where necessary." + (interactive) + (lazy-lock-fontify-region (point-min) (point-max)))) + +;; API Functions: + +(defun lazy-lock-fixup-hooks () + ;; Make sure our hooks are correct. + (remove-hook 'pre-idle-hook 'lazy-lock-pre-idle-fontify-windows) + (remove-hook 'post-command-hook 'lazy-lock-post-command-fontify-stealthily) + ;; Make sure our hooks are at the end. Font-lock in XEmacs installs + ;; its own pre-idle-hook to implement deferral (#### something that + ;; should really be merged with this file; or more likely, lazy-lock + ;; in its entirety should be merged into font-lock). + (add-hook 'pre-idle-hook 'lazy-lock-pre-idle-fontify-windows t) + (add-hook 'post-command-hook 'lazy-lock-post-command-fontify-stealthily t) + ;; Fascistically remove font-lock's after-change-function and install + ;; our own. We know better than font-lock what to do. Otherwise, + ;; revert-buffer, insert-file, etc. cause full refontification of the + ;; entire changed area. + (if lazy-lock-mode + (progn + (remove-hook 'after-change-functions 'font-lock-after-change-function + t) + (make-local-hook 'after-change-functions) + (add-hook 'after-change-functions 'lazy-lock-after-change-function + nil t)) + (remove-hook 'after-change-functions 'lazy-lock-after-change-function t) + (if font-lock-mode + (add-hook 'after-change-functions 'font-lock-after-change-function + nil t))) +) + +;; use put-nonduplicable-text-property to avoid unfriendly behavior +;; when doing undo, etc. We really don't want syntax-highlighting text +;; properties copied into strings or tracked by undo. +;; +;; #### If start-open and end-open really behaved like they are supposed to, +;; we wouldn't really need this. I kind of fixed them up, but there's still +;; a bug -- inserting text into the middle of a region of +;; (start-open t end-open t) text should cause it not to inherit, but it +;; does. + +(if lazy-lock-running-xemacs-p + (defalias 'lazy-lock-put-text-property 'put-nonduplicable-text-property) + (defalias 'lazy-lock-put-text-property 'put-text-property)) + +(defun lazy-lock-fontify-region (start end &optional buffer) + "Fontify between START and END in BUFFER where necessary." + (save-excursion + (and buffer (set-buffer buffer)) + (save-restriction + (narrow-to-region start end) + (let ((lazy-lock-stealth-lines (count-lines start end))) + (while (text-property-not-all start end 'fontified t) + (lazy-lock-fontify-stealthily)))))) + +(defun lazy-lock-after-fontify-buffer () + ;; Mark the buffer as `fontified'. + (let ((modified (buffer-modified-p)) (inhibit-read-only t) + (buffer-undo-list t) + deactivate-mark buffer-file-name buffer-file-truename) + (lazy-lock-put-text-property (point-min) (point-max) 'fontified t) + (or modified (set-buffer-modified-p nil)))) + +;; Just a cleaner-looking way of coping with Emacs' and XEmacs' `sit-for'. +(defmacro lazy-lock-sit-for (seconds &optional nodisp) + (if lazy-lock-running-xemacs-p + (` (sit-for (, seconds) (, nodisp))) + (` (sit-for (, seconds) 0 (, nodisp))))) + +;; Using `save-window-excursion' provokes `window-size-change-functions'. +;; I prefer `save-walking-excursion', of course, because I have a warped mind. +(if (fboundp 'save-selected-window) + nil + (eval-and-compile + (defmacro save-selected-window (&rest body) + "Execute the BODY forms, restoring the selected window. +Does not restore the value of point in the selected window, or anything else." + (` (let ((original-window (selected-window))) + (unwind-protect + (progn (,@ body)) + (select-window original-window)))))) + (put 'save-selected-window 'lisp-indent-function 0)) + +;; Functions for hooks: + +;; lazy-lock optimization: +;; +;; pre-idle-hook is called an awful lot -- pretty much every time the +;; mouse moves or a timeout expires, for example. On Linux (sometimes), +;; IRIX 5.x, and Solaris 2.something, it happens every 1/4 of a second +;; due to the 1/4-second timers installed to compensate for various +;; operating system deficiencies in the handling of SIGIO and SIGCHLD. +;; (Those timers cause a cycle of the event loop. They don't necessarily +;; have to, but rewriting to avoid this is fairly tricky and requires +;; having significant amounts of code called from signal handlers, which +;; (despite that fact that FSF Emacs reads its X input during a signal +;; handler ?!), is almost always a bad idea -- it's extremely easy to +;; introduce race conditions, which are very hard to track down. +;; +;; So to improve things, I added `frame-modified-tick'. This is an +;; internal counter that gets ticked any time that any internal +;; redisplay variable gets ticked. If `frame-modified-tick' is +;; the same as the last time we checked, it means that redisplay will +;; do absolutely nothing when encountering this frame, and thus we +;; can skip out immediately. This happens when the 1/4-second timer +;; fires while we're idle, or if we just move the mouse. (Moving +;; around in a buffer changes `frame-modified-tick' because the +;; internal redisplay variable "point_changed" gets ticked. We could +;; easily improve things further by adding more tick counters, mirroring +;; more closely the internal redisplay counters -- e.g. if we had +;; another counter that didn't get ticked when point moved, we could +;; tell if anything was going to happen by seeing if point is within +;; window-start and window-end, since we know that redisplay will +;; only do a window-scroll if it's not. (If window-start or window-end +;; or window-buffer or anything else changed, windows_changed or +;; some other variable will get ticked.)) +;; +;; Also, it's wise to try and avoid things that cons. Avoiding +;; `save-window-excursion', as we do, is definitely a major win +;; because that's a heavy-duty function as regards consing and such. + +(defvar lazy-lock-pre-idle-frame-modified-tick nil) +(defvar lazy-lock-pre-idle-selected-frame nil) + +(defun lazy-lock-pre-idle-fontify-windows () + ;; Do groovy things always unless we're in one of the ignored commands. + ;; The old version did the following five checks: + ;; + ;; (a) not in a macro, + ;; (b) no input pending, + ;; (c) got a real command (i.e. not an ignored command) + ;; (d) not in the minibuffer + ;; (e) no input after waiting for `lazy-lock-continuity-time'. + ;; + ;; (a), (b), and (e) are automatically taken care of by `pre-idle-hook'. + ;; I removed (d) because there doesn't seem to be any reason for it. + ;; + ;; Also, we do not have to `set-buffer' and in fact it would be + ;; incorrect to do so, since we may be being called from + ;; `accept-process-output' or whatever. + ;; + (if (memq this-command lazy-lock-ignore-commands) + (setq lazy-lock-cache-continue nil) + (setq lazy-lock-cache-continue t) + ;; #### we don't yet handle frame-modified-tick on multiple frames. + ;; handling this shouldn't be hard but I just haven't done it yet. + (if (or (eq 'all-frames lazy-lock-walk-windows) + (not (eq lazy-lock-pre-idle-selected-frame (selected-frame))) + (not (eq lazy-lock-pre-idle-frame-modified-tick + (frame-modified-tick (selected-frame))))) + (progn + ;; Do the visible parts of the buffer(s), i.e., the window(s). + (if (or (not lazy-lock-walk-windows) + (and (eq lazy-lock-walk-windows t) (one-window-p t))) + (if lazy-lock-mode (condition-case nil + (lazy-lock-fontify-window))) + (lazy-lock-fontify-walk-windows)) + (setq lazy-lock-pre-idle-selected-frame (selected-frame)) + (setq lazy-lock-pre-idle-frame-modified-tick + (frame-modified-tick (selected-frame))))))) + +(defun lazy-lock-after-change-function (beg end old-len) + (and lazy-lock-mode + (if (= beg end) + (font-lock-after-change-function beg end old-len) + (lazy-lock-put-text-property beg end 'fontified nil)))) + +;; DO NOT put this as a pre-idle hook! The sit-for messes up +;; mouse dragging. +(defun lazy-lock-post-command-fontify-stealthily () + ;; Do groovy things if (a-d) above, (e) not moving the mouse, and (f) no + ;; input after after waiting for `lazy-lock-stealth-time'. + (if (and lazy-lock-cache-continue lazy-lock-stealth-time) + (condition-case data + (if (lazy-lock-sit-for lazy-lock-stealth-time) + ;; Do the invisible parts of buffers. + (lazy-lock-fontify-walk-stealthily)) + (error (message "Fontifying stealthily... %s" data))))) + +;; In XEmacs 19.14 with pre-idle-hook we do not have to call this. +(defun lazy-lock-post-resize-fontify-windows (frame) + ;; Fontify all windows in FRAME. + (let ((lazy-lock-walk-windows t) executing-kbd-macro this-command) + (save-excursion + (save-selected-window + (select-frame frame) + (lazy-lock-pre-idle-fontify-windows))))) + +(defun lazy-lock-post-setup-emacs-fontify-windows () + ;; Fontify all windows in all frames. + (let ((lazy-lock-walk-windows 'all-frames) executing-kbd-macro this-command) + (lazy-lock-pre-idle-fontify-windows))) + +(defun lazy-lock-post-setup-ediff-control-frame () + ;; Fontify all windows in all frames when using the Ediff control frame. + (make-local-variable 'lazy-lock-walk-windows) + (setq lazy-lock-walk-windows (if (ediff-multiframe-setup-p) 'all-frames t)) + (lazy-lock-fixup-hooks)) + +;; Functions for fontification: + +(defun lazy-lock-fontify-window () + ;; Fontify the visible part of the buffer where necessary. + (let ((ws (if lazy-lock-hide-invisible + (save-excursion + (end-of-line) (forward-line (- (window-height))) (point)) + (min (max (window-start) (point-min)) (point-max)))) + (we (if lazy-lock-hide-invisible + (save-excursion + (end-of-line) (forward-line (window-height)) (point)) + (min (max (1- (window-end)) (point-min)) (point-max))))) + (if (or (/= ws lazy-lock-cache-start) (/= we lazy-lock-cache-end)) + ;; Find where we haven't `fontified' before. + (let* ((start (or (text-property-not-all ws we 'fontified t) ws)) + (end (or (text-property-any start we 'fontified t) we)) + (modified (buffer-modified-p)) (inhibit-read-only t) + ;; We do the following to prevent: undo list addition; region + ;; highlight disappearance; supersession/locking checks. + (buffer-undo-list t) + deactivate-mark buffer-file-name buffer-file-truename + ;; Ensure Emacs 19.30 syntactic fontification is always correct. + font-lock-beginning-of-syntax-function + ;; Prevent XEmacs 19.13 during fontification from messages. + font-lock-verbose) + (while (< start end) + ;; Fontify and flag the region as `fontified'. + ;; XEmacs: need to bind `font-lock-always-fontify-immediately' + ;; or we'll mess up in the presence of deferred font-locking. + (let ((font-lock-always-fontify-immediately t)) + (font-lock-after-change-function start end 0)) + (lazy-lock-put-text-property start end 'fontified t) + ;; Find the next region. + (setq start (or (text-property-not-all ws we 'fontified t) ws) + end (or (text-property-any start we 'fontified t) we))) + (setq lazy-lock-cache-start ws lazy-lock-cache-end we) + (or modified (set-buffer-modified-p nil)))))) + +(defun lazy-lock-fontify-walk-windows () + ;; Fontify windows in all required by walking through them. + (save-excursion + (save-selected-window + (condition-case nil + (walk-windows + (function (lambda (window) + (select-window window) + (if lazy-lock-mode (lazy-lock-fontify-window)))) + 'no-minibuf (eq lazy-lock-walk-windows 'all-frames)) + (wrong-type-argument + ;; Looks like the Emacs 19.28 Garbage Collection bug has hit town. + ;; Completely remove all text properties and restart. + (set-text-properties (point-min) (point-max) nil) + (turn-on-lazy-lock) + (lazy-lock-fontify-window) + (message "Fontifying window... done. (Restarted in %s)" + (buffer-name))))))) + +(defun lazy-lock-fontify-stealthily () + ;; Fontify an invisible part of the buffer where necessary. + (save-excursion + ;; Move to the end in case the character to the left is not `fontified'. + (end-of-line) + ;; Find where the next and previous regions not `fontified' begin and end. + (let ((next (text-property-not-all (point) (point-max) 'fontified t)) + (prev (let ((p (previous-single-property-change (point) 'fontified))) + (and p (> p (point-min)) p))) + (modified (buffer-modified-p)) (inhibit-read-only t) start end + ;; We do the following to prevent: undo list addition; region + ;; highlight disappearance; supersession/locking checks. + (buffer-undo-list t) + deactivate-mark buffer-file-name buffer-file-truename + ;; Ensure Emacs 19.30 syntactic fontification is always correct. + font-lock-beginning-of-syntax-function + ;; Prevent XEmacs 19.13 during fontification from spewing messages. + font-lock-verbose) + (cond ((and (null next) (null prev)) + ;; Nothing has been `fontified' yet. + (beginning-of-line 1) (setq start (point)) + (forward-line (or lazy-lock-stealth-lines (window-height))) + (setq end (point))) + ((or (null prev) + (and next (> (- (point) prev) (- next (point))))) + ;; The next region is the nearest not `fontified'. + (goto-char next) (beginning-of-line 1) (setq start (point)) + (forward-line (or lazy-lock-stealth-lines (window-height))) + ;; Maybe the region is already partially `fontified'. + (setq end (or (text-property-any next (point) 'fontified t) + (point)))) + (t + ;; The previous region is the nearest not `fontified'. + (goto-char prev) (forward-line 1) (setq end (point)) + (forward-line (- (or lazy-lock-stealth-lines (window-height)))) + ;; Maybe the region is already partially `fontified'. + (setq start + (or (previous-single-property-change prev 'fontified nil (point)) + (point))))) + ;; Fontify and flag the region as `fontified'. + ;; XEmacs: need to bind `font-lock-always-fontify-immediately' + ;; or we'll mess up in the presence of deferred font-locking. + (let ((font-lock-always-fontify-immediately t)) + (font-lock-after-change-function start end 0)) + (lazy-lock-put-text-property start end 'fontified t) + (or modified (set-buffer-modified-p nil))))) + +(defun lazy-lock-fontify-walk-stealthily () + ;; Fontify regions in all required buffers while there is no input. + (let ((buffers (buffer-list)) (continue t) fontified message-log-max) + (save-excursion + (while (and buffers continue) + (set-buffer (car buffers)) + (if (and lazy-lock-mode (lazy-lock-unfontified-p)) + ;; Fontify regions in this buffer while there is no input. + (let ((bufname (buffer-name))) + (if (and lazy-lock-stealth-verbose (not fontified)) + (message "Fontifying stealthily...")) + ;; We `save-restriction' and `widen' around everything as + ;; `lazy-lock-fontify-stealthily' doesn't and we `sit-for'. + (save-restriction (widen) (lazy-lock-fontify-stealthily)) + (while (and (lazy-lock-unfontified-p) + (setq continue (lazy-lock-sit-for + lazy-lock-stealth-nice))) + (if lazy-lock-stealth-verbose + (message "Fontifying stealthily... %2d%% of %s" + (lazy-lock-percent-fontified) bufname)) + (save-restriction (widen) (lazy-lock-fontify-stealthily))) + ;; Note that fontification occurred. + (setq fontified t))) + (setq buffers (cdr buffers)))) + (if (and lazy-lock-stealth-verbose fontified) + (message "Fontifying stealthily... %s." (if continue "done" "quit"))))) + +(defun lazy-lock-unfontified-p () + ;; Return non-nil if there is anywhere still to be `fontified'. + (save-restriction + (widen) + (text-property-not-all (point-min) (point-max) 'fontified t))) + +(defun lazy-lock-percent-fontified () + ;; Return the percentage (of characters) of the buffer that are `fontified'. + (save-restriction + (widen) + (let ((size 0) (start (point-min)) (max (point-max)) end) + (while (setq start (text-property-any start max 'fontified t)) + (setq end (or (text-property-not-all start max 'fontified t) max) + size (+ size (- end start)) + start end)) + ;; Saying "99% done" is probably better than "100% done" when it isn't. + (truncate (/ (* size 100.0) (buffer-size)))))) + +(defun lazy-lock-colour-invisible () + ;; Fontify the current buffer in `lazy-lock-invisible-face'. + (save-restriction + (widen) + (let ((face 'lazy-lock-invisible-face) + (fore (if (stringp lazy-lock-invisible-foreground) + lazy-lock-invisible-foreground + (cdr (assq 'background-color (frame-parameters))))) + (modified (buffer-modified-p)) (inhibit-read-only t) + (buffer-undo-list t) + deactivate-mark buffer-file-name buffer-file-truename) + (make-face face) + (if (not (equal (face-foreground face) fore)) + (condition-case nil + (set-face-foreground face fore) + (error (message "Unable to use foreground \"%s\"" fore)))) + (lazy-lock-put-text-property (point-min) (point-max) 'face face) + (lazy-lock-put-text-property (point-min) (point-max) 'fontified nil) + (or modified (set-buffer-modified-p nil))))) + +;; Functions for Emacs: + +;; This fix is for a number of bugs in the function in Emacs 19.28. +(if (and (not lazy-lock-running-xemacs-p) + (not (emacs-version>= 19 29))) + (defun font-lock-fontify-region (start end &optional loudly) + "Put proper face on each string and comment between START and END." + (save-excursion + (save-restriction + (widen) + (goto-char start) + (beginning-of-line) + (if loudly (message "Fontifying %s... (syntactically...)" (buffer-name))) + (let ((inhibit-read-only t) (buffer-undo-list t) + buffer-file-name buffer-file-truename + (modified (buffer-modified-p)) + (old-syntax (syntax-table)) + (synstart (if comment-start-skip + (concat "\\s\"\\|" comment-start-skip) + "\\s\"")) + (comstart (if comment-start-skip + (concat "\\s<\\|" comment-start-skip) + "\\s<")) + (startline (point)) + state prev prevstate) + (unwind-protect + (progn + (if font-lock-syntax-table + (set-syntax-table font-lock-syntax-table)) + ;; Find the state at the line-beginning before START. + (if (eq startline font-lock-cache-position) + (setq state font-lock-cache-state) + ;; Find outermost containing sexp. + (beginning-of-defun) + ;; Find the state at STARTLINE. + (while (< (point) startline) + (setq state (parse-partial-sexp (point) startline 0))) + (setq font-lock-cache-state state + font-lock-cache-position (point))) + ;; Now find the state precisely at START. + (setq state (parse-partial-sexp (point) start nil nil state)) + ;; If the region starts inside a string, show the extent of it. + (if (nth 3 state) + (let ((beg (point))) + (while (and (re-search-forward "\\s\"" end 'move) + (nth 3 (parse-partial-sexp beg (point) nil nil + state)))) + (lazy-lock-put-text-property + beg (point) 'face font-lock-string-face) + (setq state (parse-partial-sexp beg (point) + nil nil state)))) + ;; Likewise for a comment. + (if (or (nth 4 state) (nth 7 state)) + (let ((beg (point))) + (save-restriction + (narrow-to-region (point-min) end) + (condition-case nil + (progn + (re-search-backward comstart (point-min) 'move) + (forward-comment 1) + ;; forward-comment skips all whitespace, + ;; so go back to the real end of the comment. + (skip-chars-backward " \t")) + (error (goto-char end)))) + (lazy-lock-put-text-property beg (point) 'face + font-lock-comment-face) + (setq state (parse-partial-sexp beg (point) + nil nil state)))) + ;; Find each interesting place between here and END. + (while (and (< (point) end) + (setq prev (point) prevstate state) + (re-search-forward synstart end t) + (progn + ;; Clear out the fonts of what we skip over. + (remove-text-properties prev (point) '(face nil)) + ;; Verify the state at that place + ;; so we don't get fooled by \" or \;. + (setq state (parse-partial-sexp prev (point) + nil nil state)))) + (let ((here (point))) + (if (or (nth 4 state) (nth 7 state)) + ;; We found a real comment start. + (let ((beg (match-beginning 0))) + (goto-char beg) + (save-restriction + (narrow-to-region (point-min) end) + (condition-case nil + (progn + (forward-comment 1) + ;; forward-comment skips all whitespace, + ;; so go back to the real end of the comment. + (skip-chars-backward " \t")) + (error (goto-char end)))) + (lazy-lock-put-text-property + beg (point) 'face font-lock-comment-face) + (setq state (parse-partial-sexp here (point) + nil nil state))) + (if (nth 3 state) + (let ((beg (match-beginning 0))) + (while (and (re-search-forward "\\s\"" end 'move) + (nth 3 (parse-partial-sexp + here (point) nil nil state)))) + (lazy-lock-put-text-property + beg (point) 'face font-lock-string-face) + (setq state (parse-partial-sexp here (point) + nil nil state)))))) + ;; Make sure PREV is non-nil after the loop + ;; only if it was set on the very last iteration. + (setq prev nil))) + (set-syntax-table old-syntax) + (and prev + (remove-text-properties prev end '(face nil))) + (and (buffer-modified-p) + (not modified) + (set-buffer-modified-p nil)))))))) + +;; Functions for XEmacs: + +;; These fix bugs in `text-property-any' and `text-property-not-all'. They may +;; not work perfectly in 19.11 and below because `next-single-property-change' +;; is also broke and not easily fixable in Lisp. +(if (and lazy-lock-running-xemacs-p + (not (emacs-version>= 19 12))) + (progn + ;; Loop through property changes until found. This fix includes a work + ;; around which prevents a bug in `window-start' causing a barf here. + (defun text-property-any (start end prop value &optional buffer) + "Check text from START to END to see if PROP is ever `eq' to VALUE. +If so, return the position of the first character whose PROP is `eq' +to VALUE. Otherwise return nil." + (let ((start (min start end)) (end (max start end))) + (while (and start (not (eq (get-text-property start prop buffer) value))) + (setq start (next-single-property-change start prop buffer end))) + start)) + ;; No need to loop here; if it's not at START it's at the next change. + ;; However, `next-single-property-change' sometimes returns LIMIT, or + ;; `point-max', if no change is found and sometimes returns nil. + (defun text-property-not-all (start end prop value &optional buffer) + "Check text from START to END to see if PROP is ever not `eq' to VALUE. +If so, return the position of the first character whose PROP is not +`eq' to VALUE. Otherwise, return nil." + (if (not (eq value (get-text-property start prop buffer))) + start + (let ((next (next-single-property-change start prop buffer end)) + (end (or end (save-excursion (and buffer (set-buffer buffer)) + (point-max))))) + (and next (< next end) next)))))) + +;; XEmacs 19.11 function `font-lock-any-extents-p' looks for `text-prop' rather +;; than `face'. Since `font-lock-unfontify-region' only removes `face', and we +;; have non-font-lock properties hanging about, `text-prop' never gets removed. +;; Unfortunately `font-lock-any-extents-p' is inlined so we can't redefine it. +(if (and lazy-lock-running-xemacs-p + (not (emacs-version>= 19 12))) + (add-hook 'font-lock-mode-hook + (function (lambda () + (remove-hook 'after-change-functions 'font-lock-after-change-function) + (add-hook 'after-change-functions + (function (lambda (beg end old-len) + (let ((a-c-beg beg) (a-c-end end)) + (save-excursion + ;; First set `text-prop' to nil for `font-lock-any-extents-p'. + (goto-char end) (forward-line 1) (setq end (point)) + (goto-char beg) (beginning-of-line) (setq beg (point)) + (lazy-lock-put-text-property beg end 'text-prop nil) + ;; Then do the real `font-lock-after-change-function'. + (font-lock-after-change-function a-c-beg a-c-end old-len) + ;; Now set `fontified' to t to stop `lazy-lock-fontify-window'. + (lazy-lock-put-text-property beg end 'fontified t)))))))))) + +(if (and lazy-lock-running-xemacs-p (emacs-version>= 19 12)) + ;; XEmacs 19.12 font-lock.el's `font-lock-fontify-buffer' runs a hook. + (add-hook 'font-lock-after-fontify-buffer-hook + 'lazy-lock-after-fontify-buffer)) + +;; Cope with the differences between Emacs and [LX]Emacs. +(or (fboundp 'frame-parameters) + (defalias 'frame-parameters 'screen-parameters)) + +;; Install ourselves: + +;; We don't install ourselves on `font-lock-mode-hook' as other packages can be +;; used with font-lock.el, and lazy-lock.el should be dumpable without forcing +;; people to get lazy or making it difficult for people to use alternatives. +;; make sure we add after font-lock's own pre-idle-hook. +(add-hook 'window-setup-hook 'lazy-lock-post-setup-emacs-fontify-windows) +;Not needed in XEmacs 19.14: +;(add-hook 'window-size-change-functions 'lazy-lock-post-resize-fontify-windows) + +;; Package-specific. +(add-hook 'ediff-after-setup-control-frame-hooks + 'lazy-lock-post-setup-ediff-control-frame) + +;; Might as well uninstall too. Package-local symbols would be nice... +(and (fboundp 'unintern) (unintern 'lazy-lock-running-xemacs-p)) +(and (fboundp 'unintern) (unintern 'lazy-lock-sit-for)) + +;; Maybe save on the modeline? +;;(setcdr (assq 'font-lock-mode minor-mode-alist) '(" Lazy")) + +;(or (assq 'lazy-lock-mode minor-mode-alist) +; (setq minor-mode-alist (cons '(lazy-lock-mode " Lazy") minor-mode-alist))) + +;; XEmacs change: do it the right way. This works with modeline mousing. +;;;###autoload +(add-minor-mode 'lazy-lock-mode " Lazy") + +;; Provide ourselves: + +(provide 'lazy-lock) + +;;; lazy-lock.el ends here