- (save-restriction
- (widen)
- (let ((end (min (point-max) (+ start jit-lock-chunk-size)))
- (parse-sexp-lookup-properties font-lock-syntactic-keywords)
- (font-lock-beginning-of-syntax-function nil)
- (old-syntax-table (syntax-table))
- next font-lock-start font-lock-end)
- (when font-lock-syntax-table
- (set-syntax-table font-lock-syntax-table))
- (save-match-data
- (condition-case error
- ;; 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 font-lock-end (line-beginning-position 2))
- (goto-char start)
- (setq font-lock-start (line-beginning-position))
-
- ;; Fontify the chunk, and mark it as fontified.
- (font-lock-fontify-region font-lock-start font-lock-end nil)
- (add-text-properties start next '(fontified t))
-
- ;; Find the start of the next chunk, if any.
- (setq start (text-property-any next end 'fontified nil)))
-
- ((error quit)
- (message "Fontifying region...%s" error))))
-
- ;; Restore previous buffer settings.
- (set-syntax-table old-syntax-table))))))
+ (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 ((orig-start start) 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 (and start (< start end))
+ ;; 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))
+
+ ;; Make sure the contextual refontification doesn't re-refontify
+ ;; what's already been refontified.
+ (when (and jit-lock-context-unfontify-pos
+ (< jit-lock-context-unfontify-pos next)
+ (>= jit-lock-context-unfontify-pos start)
+ ;; Don't move boundary forward if we have to
+ ;; refontify previous text. Otherwise, we risk moving
+ ;; it past the end of the multiline property and thus
+ ;; forget about this multiline region altogether.
+ (not (get-text-property start 'jit-lock-defer-multiline)))
+ (setq jit-lock-context-unfontify-pos next))
+
+ ;; 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)
+ (condition-case err
+ (run-hook-with-args 'jit-lock-functions start next)
+ ;; If the user quits (which shouldn't happen in normal on-the-fly
+ ;; jit-locking), make sure the fontification will be performed
+ ;; before displaying the block again.
+ (quit (put-text-property start next 'fontified nil)
+ (funcall 'signal (car err) (cdr err))))
+
+ ;; The redisplay engine has already rendered the buffer up-to
+ ;; `orig-start' and won't notice if the above jit-lock-functions
+ ;; changed the appearance of any part of the buffer prior
+ ;; to that. So if `start' is before `orig-start', we need to
+ ;; cause a new redisplay cycle after this one so that any changes
+ ;; are properly reflected on screen.
+ ;; To make such repeated redisplay happen less often, we can
+ ;; eagerly extend the refontified region with
+ ;; jit-lock-after-change-extend-region-functions.
+ (when (< start orig-start)
+ (run-with-timer 0 nil 'jit-lock-force-redisplay
+ (current-buffer) start orig-start))
+
+ ;; Find the start of the next chunk, if any.
+ (setq start (text-property-any next end 'fontified nil))))))))
+
+(defun jit-lock-force-redisplay (buf start end)
+ "Force the display engine to re-render buffer BUF from START to END."
+ (with-current-buffer buf
+ (with-buffer-prepared-for-jit-lock
+ ;; Don't cause refontification (it's already been done), but just do
+ ;; some random buffer change, so as to force redisplay.
+ (put-text-property start end 'fontified t))))
+