in @code{c-doc-comment-style}. If it's a variable, it's prepended to
@code{font-lock-keywords}. If it's a function, it's called at mode
initialization and the result is prepended. For an example, see
-@code{javadoc-font-lock-keywords} in @file{cc-fonts.el}.
+@code{javadoc-font-lock-keywords} in @file{cc-fonts.el}. It is even
+possible, to a limited extent, to fontify constructs inside a doc
+comment with other faces. For an example, see pike autodoc comment
+style towards the end of @file{cc-fonts-el}.
If you add support for another doc comment style, please consider
contributing it: send a note to @email{bug-cc-mode@@gnu.org}.
(cc-require-when-compile 'cc-langs)
(cc-require 'cc-vars)
+(defvar c-doc-line-join-re)
+(defvar c-doc-bright-comment-start-re)
+(defvar c-doc-line-join-end-ch)
+
\f
;; Make declarations for all the `c-lang-defvar' variables in cc-langs.
(skip-chars-forward " \t\n\r\f\v")
(when (or (looking-at c-syntactic-ws-start)
(and c-opt-cpp-prefix
- (looking-at c-noise-macro-name-re)))
+ (looking-at c-noise-macro-name-re))
+ (looking-at c-doc-line-join-re))
(setq rung-end-pos (min (1+ (point)) (point-max)))
(if (setq rung-is-marked (text-property-any rung-pos rung-end-pos
(looking-at c-noise-macro-name-re))
;; Skip over a noise macro.
(goto-char (match-end 1))
+ (not (eobp)))
+
+ ((looking-at c-doc-line-join-re)
+ ;; Skip over a line join in (e.g.) Pike autodoc.
+ (goto-char (match-end 0))
+ (setq safe-start nil) ; Never cache this; the doc style could be
+ ; changed at any time.
(not (eobp)))))
;; We've searched over a piece of non-white syntactic ws. See if this
(let (;; `rung-pos' is set to a position as late as possible in the unmarked
;; part of the simple ws region.
(rung-pos (point)) next-rung-pos last-put-in-sws-pos
- rung-is-marked simple-ws-beg cmt-skip-pos)
+ rung-is-marked simple-ws-beg cmt-skip-pos
+ (doc-line-join-here (concat c-doc-line-join-re "\\=")))
;; Skip simple horizontal ws and do a quick check on the preceding
;; character to see if it's anything that can't end syntactic ws, so we can
(skip-chars-backward " \t\f")
(when (and (not (bobp))
(save-excursion
- (backward-char)
- (or (looking-at c-syntactic-ws-end)
- (and c-opt-cpp-prefix
- (looking-at c-symbol-char-key)
- (progn (c-beginning-of-current-token)
- (looking-at c-noise-macro-name-re))))))
+ (or (and
+ (memq (char-before) c-doc-line-join-end-ch) ; For speed.
+ (re-search-backward doc-line-join-here
+ (c-point 'bopl) t))
+ (progn
+ (backward-char)
+ (or (looking-at c-syntactic-ws-end)
+ (and c-opt-cpp-prefix
+ (looking-at c-symbol-char-key)
+ (progn (c-beginning-of-current-token)
+ (looking-at c-noise-macro-name-re))))))))
;; Try to find a rung position in the simple ws preceding point, so that
;; we can get a cache hit even if the last bit of the simple ws has
;; changed recently.
(looking-at c-noise-macro-name-re)))))
;; Skipped over a noise macro
(goto-char next-rung-pos)
- t)))
+ t)
+
+ ((and
+ (memq (char-before) c-doc-line-join-end-ch) ; For speed.
+ (re-search-backward doc-line-join-here (c-point 'bopl) t)))))
;; We've searched over a piece of non-white syntactic ws. See if this
;; can be cached.
(when (< cfd-match-pos cfd-limit)
;; Skip forward past comments only so we don't skip macros.
- (c-forward-comments)
+ (while
+ (progn
+ (c-forward-comments)
+ ;; The following is of use within a doc comment when a doc
+ ;; comment style has removed face properties from a construct,
+ ;; and is relying on `c-font-lock-declarations' to add them
+ ;; again.
+ (and (< (point) cfd-limit)
+ (looking-at c-doc-line-join-re)
+ (goto-char (match-end 0)))))
;; Set the position to continue at. We can avoid going over
;; the comments skipped above a second time, but it's possible
;; that the comment skipping has taken us past `cfd-prop-match'
(goto-char (or start-in-literal cfd-start-pos))
;; The only syntactic ws in macros are comments.
(c-backward-comments)
- (backward-char)
+ (or (bobp) (backward-char))
(c-beginning-of-current-token))
(start-in-literal
(not (eq (c-get-char-property (point) 'c-type)
'c-decl-end))))))
- (when (= (point) start-in-literal)
+ (when (and (= (point) start-in-literal)
+ (not (looking-at c-doc-bright-comment-start-re)))
;; Didn't find any property inside the comment, so we can
;; skip it entirely. (This won't skip past a string, but
;; that'll be handled quickly by the next
(c-lang-const c-complex-decl-matchers)
(c-lang-const c-basic-matchers-after)))
+(defun c-get-doc-comment-style ()
+ ;; Get the symbol (or list of symbols) constituting the document style.
+ ;; Return nil if there is no such, otherwise something like `autodoc'.
+ (if (consp (car-safe c-doc-comment-style))
+ (cdr-safe (or (assq c-buffer-is-cc-mode c-doc-comment-style)
+ (assq 'other c-doc-comment-style)))
+ c-doc-comment-style))
+
(defun c-compose-keywords-list (base-list)
;; Incorporate the font lock keyword lists according to
;; `c-doc-comment-style' on the given keyword list and return it.
(unless (memq c-doc-face-name c-literal-faces)
(setq c-literal-faces (cons c-doc-face-name c-literal-faces)))
- (let* ((doc-keywords
- (if (consp (car-safe c-doc-comment-style))
- (cdr-safe (or (assq c-buffer-is-cc-mode c-doc-comment-style)
- (assq 'other c-doc-comment-style)))
- c-doc-comment-style))
+ (let* ((doc-keywords (c-get-doc-comment-style))
(list (nconc (c--mapcan
(lambda (doc-style)
(let ((sym (intern
"Default expressions to highlight in Pike mode.")
(defun pike-font-lock-keywords-2 ()
+ (c-set-doc-comment-res)
(c-compose-keywords-list pike-font-lock-keywords-2))
(defun pike-font-lock-keywords-3 ()
+ (c-set-doc-comment-res)
(c-compose-keywords-list pike-font-lock-keywords-3))
(defun pike-font-lock-keywords ()
+ (c-set-doc-comment-res)
(c-compose-keywords-list pike-font-lock-keywords))
\f
;;; Doc comments.
+(defvar c-doc-line-join-re "a\\`")
+;; Matches a join of two lines in a doc comment.
+;; This should not be changed directly, but instead set by
+;; `c-setup-doc-comment-style'. This variable is used in `c-find-decl-spots'
+;; in (e.g.) autodoc style comments to bridge the gap between a "@\n" at an
+;; EOL and the token following "//!" on the next line.
+
+(defvar c-doc-bright-comment-start-re "a\\`")
+;; Matches the start of a "bright" comment, one whose contents may be
+;; fontified by, e.g., `c-font-lock-declarations'.
+
+(defvar c-doc-line-join-end-ch nil)
+;; A list of characters, each being a last character of a doc comment marker,
+;; e.g. the ! from pike autodoc's "//!".
+
+(defmacro c-set-doc-comment-re-element (suffix)
+ ;; Set the variable `c-doc-line-join-re' to a buffer local value suitable
+ ;; for the current doc comment style, or kill the local value.
+ (let ((var (intern (concat "c-doc" suffix))))
+ `(let* ((styles (c-get-doc-comment-style))
+ elts)
+ (when (atom styles)
+ (setq styles (list styles)))
+ (setq elts
+ (mapcar (lambda (style)
+ (let ((sym
+ (intern-soft
+ (concat (symbol-name style) ,suffix))))
+ (and sym
+ (boundp sym)
+ (symbol-value sym))))
+ styles))
+ (setq elts (delq nil elts))
+ (setq elts (and elts
+ (concat "\\("
+ (mapconcat #'identity elts "\\|")
+ "\\)")))
+ (if elts
+ (set (make-local-variable ',var) elts)
+ (kill-local-variable ',var)))))
+
+(defmacro c-set-doc-comment-char-list (suffix)
+ ;; Set the variable 'c-doc-<suffix>' to the list of *-<suffix>, which must
+ ;; be characters, and * represents the doc comment style.
+ (let ((var (intern (concat "c-doc" suffix))))
+ `(let* ((styles (c-get-doc-comment-style))
+ elts)
+ (when (atom styles)
+ (setq styles (list styles)))
+ (setq elts
+ (mapcar (lambda (style)
+ (let ((sym
+ (intern-soft
+ (concat (symbol-name style) ,suffix))))
+ (and sym
+ (boundp sym)
+ (symbol-value sym))))
+ styles))
+ (setq elts (delq nil elts))
+ (if elts
+ (set (make-local-variable ',var) elts)
+ (kill-local-variable ',var)))))
+
+(defun c-set-doc-comment-res ()
+ ;; Set the variables `c-doc-line-join-re' and
+ ;; `c-doc-bright-comment-start-re' from the current doc comment style(s).
+ (c-set-doc-comment-re-element "-line-join-re")
+ (c-set-doc-comment-re-element "-bright-comment-start-re")
+ (c-set-doc-comment-char-list "-line-join-end-ch"))
+
(defun c-font-lock-doc-comments (prefix limit keywords)
;; Fontify the comments between the point and LIMIT whose start
;; matches PREFIX with `c-doc-face-name'. Assumes comments have been
(goto-char comment-beg)
(while (and (progn
(c-forward-single-comment)
+ (c-put-font-lock-face comment-beg (point)
+ c-doc-face-name)
(skip-syntax-forward " ")
+ (setq comment-beg (point))
(< (point) limit))
(looking-at prefix))))
(goto-char comment-beg)
- (c-forward-single-comment))
+ (c-forward-single-comment)
+ (c-put-font-lock-face comment-beg (point) c-doc-face-name))
(if (> (point) limit) (goto-char limit))
(setq comment-beg nil)
(let ((region-end (point))
(keylist keywords) keyword matcher highlights)
- (c-put-font-lock-face region-beg region-end c-doc-face-name)
(save-restriction
;; Narrow to the doc comment. Among other things, this
;; helps by making "^" match at the start of the comment.
0 'font-lock-warning-face prepend nil)
))
+(defconst autodoc-line-join-re "@[\n\r][ \t]*/[/*]!")
+;; Matches a line continuation in autodoc comment style.
+(defconst autodoc-bright-comment-start-re "/[/*]!")
+;; Matches an autodoc comment opener.
+(defconst autodoc-line-join-end-ch ?!)
+;; The final character of `autodoc-line-join-re'.
+
(defun autodoc-font-lock-keywords ()
;; Note that we depend on that `c-current-comment-prefix' has got
;; its proper value here.
(funcall fn beg end old-len))
c-before-font-lock-functions)))))))
+(defun c-doc-fl-decl-start (pos)
+ ;; If the line containing POS is in a doc comment continued line (as defined
+ ;; by `c-doc-line-join-re'), return the position of the first line of the
+ ;; sequence. Otherwise, return nil. Point has no significance at entry to
+ ;; and exit from this function.
+ (goto-char pos)
+ (back-to-indentation)
+ (and (or (looking-at c-comment-start-regexp)
+ (memq (c-literal-type (c-literal-limits)) '(c c++)))
+ (progn
+ (end-of-line)
+ (let ((here (point)))
+ (while (re-search-backward c-doc-line-join-re (c-point 'bopl) t))
+ (and (not (eq (point) here))
+ (c-point 'bol))))))
+
+(defun c-doc-fl-decl-end (pos)
+ ;; If the line containing POS is continued by a doc comment continuation
+ ;; marker (as defined by `c-doc-line-join-re), return the position of
+ ;; the BOL at the end of the sequence. Otherwise, return nil. Point has no
+ ;; significance at entry to and exit from this function.
+ (goto-char pos)
+ (back-to-indentation)
+ (let ((here (point)))
+ (while (re-search-forward c-doc-line-join-re (c-point 'eonl) t))
+ (and (not (eq (point) here))
+ (c-point 'bonl))))
+
(defun c-fl-decl-start (pos)
;; If the beginning of the line containing POS is in the middle of a "local"
;; declaration, return the beginning of that declaration. Otherwise return
;; and OLD-LEN are not used.
(if font-lock-mode
(setq c-new-BEG
- (or (c-fl-decl-start c-new-BEG) (c-point 'bol c-new-BEG))
+ (or (c-fl-decl-start c-new-BEG) (c-doc-fl-decl-start c-new-BEG)
+ (c-point 'bol c-new-BEG))
c-new-END
- (or (c-fl-decl-end c-new-END)
+ (or (c-fl-decl-end c-new-END) (c-doc-fl-decl-end c-new-END)
(c-point 'bonl c-new-END)))))
(defun c-context-expand-fl-region (beg end)
;; "local" declaration containing BEG (see `c-fl-decl-start') or BOL BEG is
;; in. NEW-END is beginning of the line after the one END is in.
(c-save-buffer-state ()
- (cons (or (c-fl-decl-start beg) (c-point 'bol beg))
- (or (c-fl-decl-end end) (c-point 'bonl (1- end))))))
+ (cons (or (c-fl-decl-start beg) (c-doc-fl-decl-start beg)
+ (c-point 'bol beg))
+ (or (c-fl-decl-end end) (c-doc-fl-decl-end end)
+ (c-point 'bonl (1- end))))))
(defun c-before-context-fl-expand-region (beg end)
;; Expand the region (BEG END) as specified by