* Font Locking Preliminaries::
* Faces::
* Doc Comments::
+* Wrong Comment Style::
+* Found Types::
* Misc Font Locking::
* AWK Mode Font Locking::
@code{font-lock-warning-face}.
@end defvar
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node Found Types
+@comment node-name, next, previous, up
+@section ``Found Type'' handling.
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+In most languages handled by CC Mode, @dfn{found types} are recognized
+as types by their context in the source code. These contrast with
+types which are basic to a language or are declared as types (e.g. by
+@code{typedef} in C).
+
+In earlier versions of @ccmode{}, when @code{jit-lock-mode} was
+enabled in Emacs (which it is by default), found types would
+frequently fail to get fontified properly. This happened when the
+fontification functions scanned a use of the found type before
+scanning the code which caused it to be recognized.
+
+From @ccmode{} version 5.36, a timer mechanism scans the entire buffer
+for found types in the seconds immediately after starting the major
+mode. When a found type gets recognized, all its occurrences in the
+buffer get marked for (re)fontification. This scanning happens in
+short time slices interleaved with other processing, such as keyboard
+handling, so that the responsiveness of Emacs should be barely
+affected. This mechanism can be disabled (see below). It is only
+active when @code{jit-lock-mode} is also active.
+
+@defvar c-type-finder-time-slot
+@vindex type-finder-time-slot (c-)
+The approximate time in seconds that CC Mode spends in scanning source
+code before relinquishing control to other Emacs activities. The
+default value is 0.05. To disable the scanning mechanism, set this
+variable to @code{nil}.
+@end defvar
+
+@defvar c-type-finder-repeat-time
+@vindex type-finder-repeat-time (c-)
+The approximate frequency (in seconds) with which the scanning
+mechanism is triggered. This time must be greater than
+@code{c-type-finder-time-slot}. Its default value is 0.1. If a less
+powerful machine becomes sluggish due to the scanning, increase the
+value of @code{c-type-finder-repeat-time} to compensate.
+@end defvar
+
+@defvar c-type-finder-chunk-size
+@vindex type-finder-chunk-size (c-)
+The approximate size (in characters) of the buffer chunk processed as
+a unit before the scanning mechanism checks whether
+@code{c-type-finder-time-slot} seconds have passed. The default value
+is 1000. A too small value here will cause inefficiencies due to the
+initialization which happens for each chunk, whereas a too large value
+will cause the processing to consume an excessive proportion of the
+@code{c-type-finder-repeat-time}.
+@end defvar
+
@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@node Misc Font Locking
@comment node-name, next, previous, up
(defvar c-doc-line-join-end-ch)
(defvar c-syntactic-context)
(defvar c-syntactic-element)
+(defvar c-new-id-start)
+(defvar c-new-id-end)
+(defvar c-new-id-is-type)
(cc-bytecomp-defvar c-min-syn-tab-mkr)
(cc-bytecomp-defvar c-max-syn-tab-mkr)
(cc-bytecomp-defun c-clear-syn-tab)
(setq c-found-types
(make-hash-table :test #'equal :weakness nil)))
-(defun c-add-type (from to)
- ;; Add the given region as a type in `c-found-types'. If the region
- ;; doesn't match an existing type but there is a type which is equal
- ;; to the given one except that the last character is missing, then
- ;; the shorter type is removed. That's done to avoid adding all
- ;; prefixes of a type as it's being entered and font locked. This
- ;; doesn't cover cases like when characters are removed from a type
- ;; or added in the middle. We'd need the position of point when the
- ;; font locking is invoked to solve this well.
+(defun c-add-type-1 (from to)
+ ;; Add the given region as a type in `c-found-types'. Prepare occurrences
+ ;; of this new type for fontification throughout the buffer.
;;
;; This function might do hidden buffer changes.
(let ((type (c-syntactic-content from to c-recognize-<>-arglists)))
(unless (gethash type c-found-types)
- (remhash (substring type 0 -1) c-found-types)
- (puthash type t c-found-types))))
+ (puthash type t c-found-types)
+ (when (and (eq (string-match c-symbol-key type) 0)
+ (eq (match-end 0) (length type)))
+ (c-fontify-new-found-type type)))))
+
+(defun c-add-type (from to)
+ ;; Add the given region as a type in `c-found-types'. Also perform the
+ ;; actions of `c-add-type-1'. If the region is or overlaps an identifier
+ ;; which might be being typed in, don't record it. This is tested by
+ ;; checking `c-new-id-start' and `c-new-id-end'. That's done to avoid
+ ;; adding all prefixes of a type as it's being entered and font locked.
+ ;; This is a bit rough and ready, but now covers adding characters into the
+ ;; middle of an identifer.
+ ;;
+ ;; This function might do hidden buffer changes.
+ (if (and c-new-id-start c-new-id-end
+ (<= from c-new-id-end) (>= to c-new-id-start))
+ (setq c-new-id-is-type t)
+ (c-add-type-1 from to)))
(defun c-unfind-type (name)
;; Remove the "NAME" from c-found-types, if present.
(cc-bytecomp-defvar c-preprocessor-face-name)
(cc-bytecomp-defvar c-reference-face-name)
(cc-bytecomp-defvar c-block-comment-flag)
+(cc-bytecomp-defvar c-type-finder-pos)
+(cc-bytecomp-defvar c-inhibit-type-finder)
+(cc-bytecomp-defvar c-type-finder-timer)
(cc-bytecomp-defun c-fontify-recorded-types-and-refs)
(cc-bytecomp-defun c-font-lock-declarators)
(cc-bytecomp-defun c-font-lock-objc-method)
(cc-bytecomp-defun c-font-lock-invalid-string)
+(cc-bytecomp-defun c-before-context-fl-expand-region)
\f
;; Note that font-lock in XEmacs doesn't expand face names as
;; This function does hidden buffer changes.
;;(message "c-font-lock-complex-decl-prepare %s %s" (point) limit)
-
- ;; Clear the list of found types if we start from the start of the
- ;; buffer, to make it easier to get rid of misspelled types and
- ;; variables that have gotten recognized as types in malformed code.
- (when (bobp)
- (c-clear-found-types))
-
(c-skip-comments-and-strings limit)
(when (< (point) limit)
nil))))
+(defun c-find-types-background (start limit)
+ ;; Find any "found types" between START and LIMIT. Allow any such types to
+ ;; be entered into `c-found-types' by the action of `c-forward-name' or
+ ;; `c-forward-type' called from this function. This process also causes
+ ;; occurrences of the type to be prepared for fontification throughout the
+ ;; buffer.
+ ;;
+ ;; Return POINT at the end of the function. This should be at or after
+ ;; LIMIT, and not later than the next decl-spot after LIMIT.
+ ;;
+ ;; This function is called from the timer `c-type-finder-timer'. It may do
+ ;; hidden buffer changes.
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char start)
+ ;; If we're in a (possibly large) literal, skip over it.
+ (let ((lit-bounds (nth 2 (c-full-pp-to-literal (point)))))
+ (if lit-bounds
+ (goto-char (cdr lit-bounds))))
+ (when (< (point) limit)
+ (let (;; o - 'decl if we're in an arglist containing declarations
+ ;; (but if `c-recognize-paren-inits' is set it might also be
+ ;; an initializer arglist);
+ ;; o - '<> if the arglist is of angle bracket type;
+ ;; o - 'arglist if it's some other arglist;
+ ;; o - nil, if not in an arglist at all. This includes the
+ ;; parenthesized condition which follows "if", "while", etc.
+ context
+ ;; A list of starting positions of possible type declarations, or of
+ ;; the typedef preceding one, if any.
+ last-cast-end
+ ;; The result from `c-forward-decl-or-cast-1'.
+ decl-or-cast
+ ;; The maximum of the end positions of all the checked type
+ ;; decl expressions in the successfully identified
+ ;; declarations. The position might be either before or
+ ;; after the syntactic whitespace following the last token
+ ;; in the type decl expression.
+ (max-type-decl-end 0)
+ ;; Same as `max-type-decl-*', but used when we're before
+ ;; `token-pos'.
+ (max-type-decl-end-before-token 0)
+ )
+ (goto-char start)
+ (c-find-decl-spots
+ limit
+ c-decl-start-re
+ nil ; (eval c-maybe-decl-faces)
+
+ (lambda (match-pos inside-macro &optional toplev)
+ ;; Note to maintainers: don't use `limit' inside this lambda form;
+ ;; c-find-decl-spots sometimes narrows to less than `limit'.
+ (if (and c-macro-with-semi-re
+ (looking-at c-macro-with-semi-re))
+ ;; Don't do anything more if we're looking at something that
+ ;; can't start a declaration.
+ t
+
+ ;; Set `context' and `c-restricted-<>-arglists'. Look for
+ ;; "<" for the sake of C++-style template arglists.
+ ;; "Ignore "(" when it's part of a control flow construct
+ ;; (e.g. "for (").
+ (let ((got-context
+ (c-get-fontification-context
+ match-pos
+ (< match-pos (if inside-macro
+ max-type-decl-end-before-token
+ max-type-decl-end))
+ toplev)))
+ (setq context (car got-context)
+ c-restricted-<>-arglists (cdr got-context)))
+
+ ;; In QT, "more" is an irritating keyword that expands to nothing.
+ ;; We skip over it to prevent recognition of "more slots: <symbol>"
+ ;; as a bitfield declaration.
+ (when (and (c-major-mode-is 'c++-mode)
+ (looking-at
+ (concat "\\(more\\)\\([^" c-symbol-chars "]\\|$\\)")))
+ (goto-char (match-end 1))
+ (c-forward-syntactic-ws))
+
+ ;; Now analyze the construct. This analysis will cause
+ ;; `c-forward-name' and `c-forward-type' to call `c-add-type',
+ ;; triggering the desired recognition and fontification of
+ ;; these found types.
+ (when (not (eq context 'not-decl))
+ (setq decl-or-cast
+ (c-forward-decl-or-cast-1
+ match-pos context last-cast-end))
+
+ (cond
+ ((eq decl-or-cast 'cast)
+ ;; Save the position after the previous cast so we can feed
+ ;; it to `c-forward-decl-or-cast-1' in the next round. That
+ ;; helps it discover cast chains like "(a) (b) c".
+ (setq last-cast-end (point))
+ nil)
+ (decl-or-cast
+ ;; We've found a declaration.
+
+ ;; Set `max-type-decl-end' or `max-type-decl-end-before-token'
+ ;; under the assumption that we're after the first type decl
+ ;; expression in the declaration now. That's not really true;
+ ;; we could also be after a parenthesized initializer
+ ;; expression in C++, but this is only used as a last resort
+ ;; to slant ambiguous expression/declarations, and overall
+ ;; it's worth the risk to occasionally fontify an expression
+ ;; as a declaration in an initializer expression compared to
+ ;; getting ambiguous things in normal function prototypes
+ ;; fontified as expressions.
+ (if inside-macro
+ (when (> (point) max-type-decl-end-before-token)
+ (setq max-type-decl-end-before-token (point)))
+ (when (> (point) max-type-decl-end)
+ (setq max-type-decl-end (point)))))
+ (t t))))))))
+ (point))))
+
+(defun c-type-finder-timer-func ()
+ ;; A CC Mode idle timer function for finding "found types". It triggers
+ ;; every `c-type-finder-repeat-time' seconds and processes buffer chunks of
+ ;; size around `c-type-finder-chunk-size' characters, and runs for (a little
+ ;; over) `c-type-finder-time-slot' seconds. The types it finds are inserted
+ ;; into `c-found-types', and their occurrences throughout the buffer are
+ ;; prepared for fontification.
+ (when (and c-type-finder-time-slot
+ (boundp 'font-lock-support-mode)
+ (eq font-lock-support-mode 'jit-lock-mode))
+ (if c-inhibit-type-finder ; No processing immediately after a GC operation.
+ (setq c-inhibit-type-finder nil)
+ (let* ((stop-time (+ (float-time) c-type-finder-time-slot))
+ (buf-list (buffer-list)))
+ ;; One CC Mode buffer needing processing each time around this loop.
+ (while (and buf-list
+ (< (float-time) stop-time))
+ ;; Cdr through BUF-LIST to find the next buffer needing processing.
+ (while (and buf-list
+ (not (with-current-buffer (car buf-list) c-type-finder-pos)))
+ (setq buf-list (cdr buf-list)))
+ (when buf-list
+ (with-current-buffer (car buf-list)
+ ;; (message "%s" (current-buffer)) ; Useful diagnostic.
+ (save-restriction
+ (widen)
+ ;; Process one `c-type-finder-chunk-size' chunk each time
+ ;; around this loop.
+ (while (and c-type-finder-pos
+ (< (float-time) stop-time))
+ ;; Process one chunk per iteration.
+ (save-match-data
+ (c-save-buffer-state
+ (case-fold-search
+ (beg (marker-position c-type-finder-pos))
+ (end (min (+ beg c-type-finder-chunk-size) (point-max)))
+ (region (c-before-context-fl-expand-region beg end)))
+ (setq beg (car region)
+ end (cdr region))
+ (setq beg (max (c-find-types-background beg end) end))
+ (move-marker c-type-finder-pos
+ (if (save-excursion (goto-char beg) (eobp))
+ nil
+ beg))
+ (when (not (marker-position c-type-finder-pos))
+ (setq c-type-finder-pos nil))))))))))))
+ ;; Set the timer to run again.
+ (setq c-type-finder-timer
+ (run-at-time c-type-finder-repeat-time nil #'c-type-finder-timer-func)))
+
(defun c-font-lock-enum-body (limit)
;; Fontify the identifiers of each enum we find by searching forward.
;;
;; defvar will install its default value later on.
(makunbound def-var)))
+;; `c-re-redisplay-timer' is a timer which, when triggered, causes a
+;; redisplay.
+(defvar c-re-redisplay-timer nil)
+
+(defun c-force-redisplay (start end)
+ ;; Force redisplay immediately. This assumes `font-lock-support-mode' is
+ ;; 'jit-lock-mode. Set the variable `c-re-redisplay-timer' to nil.
+ (jit-lock-force-redisplay (copy-marker start) (copy-marker end))
+ (setq c-re-redisplay-timer nil))
+
+(defun c-fontify-new-found-type (type)
+ ;; Cause the fontification of TYPE, a string, wherever it occurs in the
+ ;; buffer. If TYPE is currently displayed in a window, cause redisplay to
+ ;; happen "instantaneously". These actions are done only when jit-lock-mode
+ ;; is active.
+ (when (and (boundp 'font-lock-support-mode)
+ (eq font-lock-support-mode 'jit-lock-mode))
+ (c-save-buffer-state
+ ((window-boundaries
+ (mapcar (lambda (win)
+ (cons (window-start win)
+ (window-end win)))
+ (get-buffer-window-list (current-buffer) 'no-mini t)))
+ (target-re (concat "\\_<" type "\\_>")))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (while (re-search-forward target-re nil t)
+ (put-text-property (match-beginning 0) (match-end 0)
+ 'fontified nil)
+ (dolist (win-boundary window-boundaries)
+ (when (and (< (match-beginning 0) (cdr win-boundary))
+ (> (match-end 0) (car win-boundary))
+ (c-get-char-property (match-beginning 0) 'fontified)
+ (not c-re-redisplay-timer))
+ (setq c-re-redisplay-timer
+ (run-with-timer 0 nil #'c-force-redisplay
+ (match-beginning 0) (match-end 0)))))))))))
+
\f
;;; C.
; '
(require 'cc-fonts) ;)
+(defvar c-type-finder-timer nil)
+;; The variable which holds the repeating idle timer which triggers off the
+;; background type finding search.
+
+(defvar c-inhibit-type-finder nil)
+;; When non-nil (set by `c-post-gc-hook') don't perform the type finding
+;; activities the next time `c-type-finder-timer' triggers. This ensures
+;; keyboard/mouse input will be dealt with when garbage collection is taking a
+;; large portion of CPU time.
+
;; The following three really belong to cc-fonts.el, but they are required
;; even when cc-fonts.el hasn't been loaded (this happens in XEmacs when
;; font-lock-mode is nil).
(when c-buffer-is-cc-mode
(save-restriction
(widen)
+ (let ((lst (buffer-list)))
+ (catch 'found
+ (dolist (b lst)
+ (if (and (not (eq b (current-buffer)))
+ (with-current-buffer b
+ c-buffer-is-cc-mode))
+ (throw 'found nil)))
+ (remove-hook 'post-command-hook 'c-post-command)
+ (remove-hook 'post-gc-hook 'c-post-gc-hook)
+ (and c-type-finder-timer
+ (progn (cancel-timer c-type-finder-timer)
+ (setq c-type-finder-timer nil)))))
(c-save-buffer-state ()
(c-clear-char-properties (point-min) (point-max) 'category)
(c-clear-char-properties (point-min) (point-max) 'syntax-table)
;; currently no such text property.
(make-variable-buffer-local 'c-max-syn-tab-mkr)
+;; `c-type-finder-pos' is a marker marking the current place in a CC Mode
+;; buffer which is due to be searched next for "found types", or nil if the
+;; searching is complete.
+(defvar c-type-finder-pos nil)
+(make-variable-buffer-local 'c-type-finder-pos)
+
(defun c-basic-common-init (mode default-style)
"Initialize the syntax handling routines and the line breaking/filling code.
Intended to be used by other packages that embed CC Mode.
;; would do since font-lock uses a(n implicit) depth of 0) so we don't need
;; c-after-font-lock-init.
(add-hook 'after-change-functions 'c-after-change nil t)
+ (add-hook 'post-command-hook 'c-post-command)
+ (setq c-type-finder-pos
+ (save-restriction
+ (widen)
+ (move-marker (make-marker) (point-min))))
+
+ ;; Install the functionality for seeking "found types" at mode startup:
+ (or c-type-finder-timer
+ (setq c-type-finder-timer
+ (run-at-time
+ c-type-finder-repeat-time nil #'c-type-finder-timer-func)))
+ (add-hook 'post-gc-hook #'c-post-gc-hook)
+
(when (boundp 'font-lock-extend-after-change-region-function)
(set (make-local-variable 'font-lock-extend-after-change-region-function)
'c-extend-after-change-region))) ; Currently (2009-05) used by all
;; confused by already processed single quotes.
(narrow-to-region (point) (point-max))))))
+;; The next two variables record the bounds of an identifier currently being
+;; typed in. These are used to prevent such a partial identifier being
+;; recorded as a found type by c-add-type.
+(defvar c-new-id-start nil)
+(make-variable-buffer-local 'c-new-id-start)
+(defvar c-new-id-end nil)
+(make-variable-buffer-local 'c-new-id-end)
+;; The next variable, when non-nil, records that the previous two variables
+;; define a type.
+(defvar c-new-id-is-type nil)
+(make-variable-buffer-local 'c-new-id-is-type)
+
+(defun c-update-new-id (end)
+ ;; Note the bounds of any identifier that END is in or just after, in
+ ;; `c-new-id-start' and `c-new-id-end'. Otherwise set these variables to
+ ;; nil.
+ (save-excursion
+ (goto-char end)
+ (let ((id-beg (c-on-identifier)))
+ (setq c-new-id-start id-beg
+ c-new-id-end (and id-beg
+ (progn (c-end-of-current-token) (point)))))))
+
+
+(defun c-post-command ()
+ ;; If point was inside of a new identifier and no longer is, record that
+ ;; fact.
+ (when (and c-buffer-is-cc-mode
+ c-new-id-start c-new-id-end
+ (or (> (point) c-new-id-end)
+ (< (point) c-new-id-start)))
+ (when c-new-id-is-type
+ (c-add-type-1 c-new-id-start c-new-id-end))
+ (setq c-new-id-start nil
+ c-new-id-end nil
+ c-new-id-is-type nil)))
+
+(defun c-post-gc-hook (&optional _stats) ; For XEmacs.
+ (setq c-inhibit-type-finder t))
+
(defun c-before-change (beg end)
;; Function to be put on `before-change-functions'. Primarily, this calls
;; the language dependent `c-get-state-before-change-functions'. It is
(unless (c-called-from-text-property-change-p)
(save-restriction
(widen)
+ ;; Clear the list of found types if we make a change at the start of the
+ ;; buffer, to make it easier to get rid of misspelled types and
+ ;; variables that have gotten recognized as types in malformed code.
+ (when (eq beg (point-min))
+ (c-clear-found-types))
(if c-just-done-before-change
- ;; We have two consecutive calls to `before-change-functions' without
- ;; an intervening `after-change-functions'. An example of this is bug
- ;; #38691. To protect CC Mode, assume that the entire buffer has
- ;; changed.
+ ;; We have two consecutive calls to `before-change-functions'
+ ;; without an intervening `after-change-functions'. An example of
+ ;; this is bug #38691. To protect CC Mode, assume that the entire
+ ;; buffer has changed.
(setq beg (point-min)
end (point-max)
c-just-done-before-change 'whole-buffer)
c->-as-paren-syntax)
(c-clear-char-property-with-value beg end 'syntax-table nil)))
+ (c-update-new-id end)
(c-trim-found-types beg end old-len) ; maybe we don't
; need all of these.
(c-invalidate-sws-region-after beg end old-len)
:type 'boolean
:group 'c)
+(defcustom c-type-finder-time-slot 0.05
+ "The length in seconds of a background type search time slot.
+
+In CC Mode modes, \"found types\" wouldn't always get cleanly
+fontified without the background searching for them which happens
+in the seconds after starting Emacs or initializing the major
+mode.
+
+This background searching can be disabled by setting this option
+to nil."
+ :type '(choice (const :tag "disabled" nil)
+ number)
+ :group 'c)
+
+(defcustom c-type-finder-repeat-time 0.1
+ "The interval, in seconds, at which background type searches occur.
+
+This interval must be greater than `c-type-finder-time-slot'."
+ :type 'number
+ :group 'c)
+
+(defcustom c-type-finder-chunk-size 1000
+ "The size, in characters, of a chunk for background type search.
+
+Chunks of this size are searched atomically for \"found types\"
+just after starting Emacs or initializing the major mode.
+
+This chunk size is a balance between efficiency (with larger
+values) and responsiveness of the keyboard (with smaller values).
+See also `c-type-finder-time-slot'."
+ :type 'integer
+ :group 'c)
+
(define-widget 'c-extra-types-widget 'radio
"Internal CC Mode widget for the `*-font-lock-extra-types' variables."
:args '((const :tag "none" nil)