;; Buffer local variables defining the region to be fontified by a font lock
;; after-change function. They are set in c-after-change to
-;; after-change-function's BEG and END, and may be modified by a
-;; `c-before-font-lock-function'.
+;; after-change-functions' BEG and END, and may be modified by functions in
+;; `c-before-font-lock-functions'.
(defvar c-new-BEG 0)
(make-variable-buffer-local 'c-new-BEG)
(defvar c-new-END 0)
; with a c-cpp-delimiter category property
(setq c-old-EOM (point)))
+(defun c-extend-font-lock-region-for-macros (begg endd &optional old-len)
+ ;; Extend the region (BEGG ENDD) to cover all (possibly changed)
+ ;; preprocessor macros; return the cons (new-BEG . new-END). OLD-LEN should
+ ;; be either the old length parameter when called from an
+ ;; after-change-function, or nil otherwise. This defun uses the variables
+ ;; c-old-BOM, c-new-BOM.
+ ;;
+ ;; Point is undefined on both entry and exit to this function. The buffer
+ ;; will have been widened on entry.
+ (let (limits new-beg new-end)
+ (goto-char c-old-BOM) ; already set to old start of macro or begg.
+ (setq new-beg
+ (min begg
+ (if (setq limits (c-state-literal-at (point)))
+ (cdr limits) ; go forward out of any string or comment.
+ (point))))
+
+ (goto-char endd)
+ (if (setq limits (c-state-literal-at (point)))
+ (goto-char (car limits))) ; go backward out of any string or comment.
+ (if (c-beginning-of-macro)
+ (c-end-of-macro))
+ (setq new-end (max endd
+ (if old-len
+ (+ (- c-old-EOM old-len) (- endd begg))
+ c-old-EOM)
+ (point)))
+ (cons new-beg new-end)))
+
(defun c-neutralize-CPP-line (beg end)
;; BEG and END bound a region, typically a preprocessor line. Put a
;; "punctuation" syntax-table property on syntactically obtrusive
;; Note: SPEED _MATTERS_ IN THIS FUNCTION!!!
;;
;; This function might make hidden buffer changes.
- (c-save-buffer-state (limits)
+ (c-save-buffer-state (new-bounds)
;; First determine the region, (c-new-BEG c-new-END), which will get font
;; locked. It might need "neutralizing". This region may not start
;; inside a string, comment, or macro.
- (goto-char c-old-BOM) ; already set to old start of macro or begg.
- (setq c-new-BEG
- (min c-new-BEG
- (if (setq limits (c-state-literal-at (point)))
- (cdr limits) ; go forward out of any string or comment.
- (point))))
-
- (goto-char endd)
- (if (setq limits (c-state-literal-at (point)))
- (goto-char (car limits))) ; go backward out of any string or comment.
- (if (c-beginning-of-macro)
- (c-end-of-macro))
- (setq c-new-END (max c-new-END
- (+ (- c-old-EOM old-len) (- endd begg))
- (point)))
-
+ (setq new-bounds (c-extend-font-lock-region-for-macros
+ c-new-BEG c-new-END old-len))
+ (setq c-new-BEG (car new-bounds)
+ c-new-END (cdr new-bounds))
;; Clear all old relevant properties.
(c-clear-char-property-with-value c-new-BEG c-new-END 'syntax-table '(1))
(c-clear-char-property-with-value c-new-BEG c-new-END 'category 'c-cpp-delimiter)
c-get-state-before-change-functions))
))))
+(defvar c-in-after-change-fontification nil)
+(make-variable-buffer-local 'c-in-after-change-fontification)
+;; A flag to prevent region expanding stuff being done twice for after-change
+;; fontification.
+
(defun c-after-change (beg end old-len)
;; Function put on `after-change-functions' to adjust various caches
;; etc. Prefer speed to finesse here, since there will be an order
;; larger than (beg end).
(setq c-new-BEG beg
c-new-END end)
+ (setq c-in-after-change-fontification t)
(save-excursion
(mapc (lambda (fn)
(funcall fn beg end old-len))
c-before-font-lock-functions))))))
-(defun c-set-fl-decl-start (beg end old-len)
- ;; If the beginning of line containing c-new-BEG is in the middle of a
- ;; "local" declaration (i.e. one which does not start outside of braces
- ;; enclosing this pos, such as a struct), set c-new-BEG to (at most) the
- ;; beginning of that declaration. Note that declarations, in this sense,
- ;; can be nested. c-new-BEG will be used later by c-font-lock-declarations.
+(defun c-set-fl-decl-start (pos)
+ ;; If the beginning of the line containing POS is in the middle of a "local"
+ ;; declaration (i.e. one which does not start outside of braces enclosing
+ ;; POS, such as a struct), return the beginning of that declaration.
+ ;; Otherwise return POS. Note that declarations, in this sense, can be
+ ;; nested.
;;
- ;; This function is an element of c-before-font-lock-functions, being called
- ;; (indirectly) from an after-change function. The after-change-functions'
- ;; parameters BEG, OLD and OLD-LEN are ignored here.
- (when font-lock-mode
- (goto-char (c-point 'bol c-new-BEG))
- (let ((lit-limits (c-literal-limits))
- bod-lim bo-decl)
-
- (when lit-limits ; Comment or string.
- (goto-char (car lit-limits)))
- (setq bod-lim (max (- (point) 500) (point-min)))
-
- (while
- ;; Go to a less nested declaration each time round this loop.
- (and
- (eq (car (c-beginning-of-decl-1 bod-lim)) 'same)
- (progn (setq bo-decl (point))
- ;; Are we looking at a keyword such as "template" or
- ;; "typedef" which can decorate a type, or the type itself?
- (when (or (looking-at c-prefix-spec-kwds-re)
- (c-forward-type t))
- ;; We've found another candidate position.
- (setq c-new-BEG (min c-new-BEG bo-decl))
- (goto-char bo-decl))
- t)
- ;; Try and go out a level to search again.
- (progn
- (c-backward-syntactic-ws bod-lim)
- (or (memq (char-before) '(?\( ?\[))
- (and (eq (char-before) ?\<)
- (eq (c-get-char-property
- (1- (point)) 'syntax-table)
- c-<-as-paren-syntax))))
- (not (bobp)))
- (backward-char))))) ; back over (, [, <.
-
+ ;; This function is called indirectly from font locking stuff - either from
+ ;; c-after-change (to prepare for after-change font-lockng) or from font
+ ;; lock context (etc.) fontification.
+ (let ((lit-limits (c-literal-limits))
+ (new-pos pos)
+ bod-lim bo-decl)
+ (goto-char (c-point 'bol new-pos))
+ (when lit-limits ; Comment or string.
+ (goto-char (car lit-limits)))
+ (setq bod-lim (max (- (point) 500) (point-min)))
+
+ (while
+ ;; Go to a less nested declaration each time round this loop.
+ (and
+ (eq (car (c-beginning-of-decl-1 bod-lim)) 'same)
+ (progn (setq bo-decl (point))
+ ;; Are we looking at a keyword such as "template" or
+ ;; "typedef" which can decorate a type, or the type itself?
+ (when (or (looking-at c-prefix-spec-kwds-re)
+ (c-forward-type t))
+ ;; We've found another candidate position.
+ (setq new-pos (min new-pos bo-decl))
+ (goto-char bo-decl))
+ t)
+ ;; Try and go out a level to search again.
+ (progn
+ (c-backward-syntactic-ws bod-lim)
+ (or (memq (char-before) '(?\( ?\[))
+ (and (eq (char-before) ?\<)
+ (eq (c-get-char-property
+ (1- (point)) 'syntax-table)
+ c-<-as-paren-syntax))))
+ (not (bobp)))
+ (backward-char))
+ new-pos)) ; back over (, [, <.
+
+(defun c-change-set-fl-decl-start (beg end old-len)
+ ;; Set c-new-BEG to the beginning of a "local" declaration if it('s BOL) is
+ ;; inside one. This is called from an after-change-function, but the
+ ;; parameters BEG END and OLD-LEN are ignored. See `c-set-fl-decl-start'
+ ;; for the detailed functionality.
+ (if font-lock-mode
+ (setq c-new-BEG (c-set-fl-decl-start c-new-BEG))))
+
+(defun c-context-set-fl-decl-start (beg end)
+ ;; Return a cons (NEW-BEG . END), where NEW-BEG is the beginning of a
+ ;; "local" declaration (BOL at) NEW is inside or BEG. See
+ ;; `c-set-fl-decl-start' for the detailed functionality.
+ (cons (c-set-fl-decl-start beg) end))
+
+(defvar c-standard-font-lock-fontify-region-function nil
+ "Standard value of `font-lock-fontify-region-function'")
+
+(defun c-font-lock-fontify-region (beg end &optional verbose)
+ ;; Effectively advice around `font-lock-fontify-region' which extends the
+ ;; region (BEG END), for example, to avoid context fontification chopping
+ ;; off the start of the context. Do not do anything if it's already been
+ ;; done (i.e. from and after-change fontification. An example (C++) where
+ ;; this used to happen is this:
+ ;;
+ ;; template <typename T>
+ ;;
+ ;;
+ ;; void myfunc(T* p) {}
+ ;;
+ ;; Type a space in the first blank line, and the fontification of the next
+ ;; line was fouled up by context fontification.
+ (let ((new-beg beg) (new-end end) new-region)
+ (if c-in-after-change-fontification
+ (setq c-in-after-change-fontification nil)
+ (save-restriction
+ (widen)
+ (save-excursion
+ (mapc (lambda (fn)
+ (setq new-region (funcall fn new-beg new-end))
+ (setq new-beg (car new-region) new-end (cdr new-region)))
+ c-before-context-fontification-functions))))
+ (funcall c-standard-font-lock-fontify-region-function
+ new-beg new-end verbose)))
+
(defun c-after-font-lock-init ()
- ;; Put on `font-lock-mode-hook'.
+ ;; Put on `font-lock-mode-hook'. This function ensures our after-change
+ ;; function will get excuted before the font-lock one. Amongst other
+ ;; things.
(remove-hook 'after-change-functions 'c-after-change t)
- (add-hook 'after-change-functions 'c-after-change nil t))
+ (add-hook 'after-change-functions 'c-after-change nil t)
+ (setq c-standard-font-lock-fontify-region-function
+ (default-value 'font-lock-fontify-region-function)))
(defun c-font-lock-init ()
"Set up the font-lock variables for using the font-lock support in CC Mode.
This does not load the font-lock package. Use after
-`c-basic-common-init' and after cc-fonts has been loaded."
+`c-basic-common-init' and after cc-fonts has been loaded.
+This function is called from `c-common-init', once per mode initialization."
(set (make-local-variable 'font-lock-defaults)
`(,(if (c-major-mode-is 'awk-mode)
c-beginning-of-syntax
(font-lock-mark-block-function
. c-mark-function)))
+
+ (make-local-variable 'font-lock-fontify-region-function)
+ (setq font-lock-fontify-region-function 'c-font-lock-fontify-region)
+
(if (featurep 'xemacs)
(make-local-hook 'font-lock-mode-hook))
(add-hook 'font-lock-mode-hook 'c-after-font-lock-init nil t))