From d9f62fceaf2915c67f6917c668af6ff4aacc26a7 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Thu, 2 May 2019 20:53:47 +0000 Subject: Fix fontification of first item in CC Mode macro without parentheses * lisp/progmodes/cc-engine.el (c-find-decl-prefix-search): Handle the new matching possibility (of a #define construct) in the new c-decl-prefix-or-start-re. (c-find-decl-spots): Allow the initial search for an in-macro starting point settle on the # of #define, to facilitate the regexp matching in c-find-decl-prefix-search. * lisp/progmodes/cc-langs.el (c-anchored-hash-define-no-parens): New lang const. (c-literal-start-regexp): Correct what was always supposed to be a "generic string" regexp element. (c-decl-prefix-or-start-re): Enhance also to match "#define ". (c-dposr-cpp-macro-depth): New lang variable and lang constant. --- lisp/progmodes/cc-engine.el | 45 +++++++++++++++++++++++++++++++++------------ lisp/progmodes/cc-langs.el | 44 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index f9e570e9f3f..7e6a46ea6e0 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -5692,7 +5692,10 @@ comment at the start of cc-engine.el for more info." (setq cfd-re-match cfd-limit) nil) ((c-got-face-at - (if (setq cfd-re-match (match-end 1)) + (if (setq cfd-re-match + (or (match-end 1) + (and c-dposr-cpp-macro-depth + (match-end (1+ c-dposr-cpp-macro-depth))))) ;; Matched the end of a token preceding a decl spot. (progn (goto-char cfd-re-match) @@ -5703,15 +5706,19 @@ comment at the start of cc-engine.el for more info." c-literal-faces) ;; Pseudo match inside a comment or string literal. Skip out ;; of comments and string literals. - (while (progn - (unless - (and (match-end 1) - (c-got-face-at (1- (point)) c-literal-faces) - (not (c-got-face-at (point) c-literal-faces))) - (goto-char (c-next-single-property-change - (point) 'face nil cfd-limit))) - (and (< (point) cfd-limit) - (c-got-face-at (point) c-literal-faces)))) + (while + (progn + (unless + (and + (or (match-end 1) + (and c-dposr-cpp-macro-depth + (match-end (1+ c-dposr-cpp-macro-depth)))) + (c-got-face-at (1- (point)) c-literal-faces) + (not (c-got-face-at (point) c-literal-faces))) + (goto-char (c-next-single-property-change + (point) 'face nil cfd-limit))) + (and (< (point) cfd-limit) + (c-got-face-at (point) c-literal-faces)))) t) ; Continue the loop over pseudo matches. ((and c-opt-identifier-concat-key (match-string 1) @@ -5863,7 +5870,7 @@ comment at the start of cc-engine.el for more info." ;; before the point, and do the first `c-decl-prefix-or-start-re' ;; search unless we're at bob. - (let (start-in-literal start-in-macro syntactic-pos) + (let (start-in-literal start-in-macro syntactic-pos hash-define-pos) ;; Must back up a bit since we look for the end of the previous ;; statement or declaration, which is earlier than the first ;; returned match. @@ -6018,7 +6025,21 @@ comment at the start of cc-engine.el for more info." ;; The only syntactic ws in macros are comments. (c-backward-comments) (or (bobp) (backward-char)) - (c-beginning-of-current-token)) + (c-beginning-of-current-token) + ;; If we're in a macro without argument parentheses, we could have + ;; now ended up at the macro's identifier. We need to be at #define + ;; for `c-find-decl-prefix-search' to find the first token of the + ;; macro's expansion. + (when (and (c-on-identifier) + (setq hash-define-pos + (save-excursion + (and + (zerop (c-backward-token-2 2)) ; over define, # + (save-excursion + (beginning-of-line) + (looking-at c-opt-cpp-macro-define-id)) + (point))))) + (goto-char hash-define-pos))) (start-in-literal ;; If we're in a comment it can only be the closest diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 00c581a06a9..8b7e4ef7c09 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -979,6 +979,14 @@ definition, or nil if the language doesn't have any." (c-lang-defvar c-opt-cpp-macro-define-id (c-lang-const c-opt-cpp-macro-define-id)) +(c-lang-defconst c-anchored-hash-define-no-parens + ;; Regexp matching everything up to the end of a cpp define which has no + ;; argument parentheses. Or nil in languages which don't have them. + t (if (c-lang-const c-opt-cpp-macro-define) + (concat (c-lang-const c-anchored-cpp-prefix) + (c-lang-const c-opt-cpp-macro-define) + "[ \t]+\\(\\sw\\|_\\)+\\([^(a-zA-Z0-9_]\\|$\\)"))) + (c-lang-defconst c-cpp-expr-directives "List of cpp directives (without the prefix) that are followed by an expression." @@ -1614,7 +1622,7 @@ starter." t (concat (c-lang-const c-comment-start-regexp) "\\|" (if (memq 'gen-string-delim c-emacs-features) - "\"|" + "\"\\|\\s|" "\""))) (c-lang-defvar c-literal-start-regexp (c-lang-const c-literal-start-regexp)) @@ -3183,24 +3191,40 @@ constructs." ;; token that might precede such a construct, e.g. ';', '}' or '{'. ;; It's built from `c-decl-prefix-re'. ;; - ;; If the first submatch did not match, the match of the whole - ;; regexp is taken to be at the first token in the declaration. - ;; `c-decl-start-re' is not checked in this case. + ;; If the first submatch did not match, we have either a #define construct + ;; without parentheses or the match of the whole regexp is taken to be at + ;; the first token in the declaration. `c-decl-start-re' is not checked in + ;; these cases. ;; ;; Design note: The reason the same regexp is used to match both ;; tokens that precede declarations and start them is to avoid an ;; extra regexp search from the previous declaration spot in ;; `c-find-decl-spots'. Users of `c-find-decl-spots' also count on - ;; that it finds all declaration/cast/label starts in approximately + ;; it finding all declaration/cast/label starts in approximately ;; linear order, so we can't do the searches in two separate passes. - t (if (c-lang-const c-decl-start-kwds) - (concat (c-lang-const c-decl-prefix-re) - "\\|" - (c-make-keywords-re t (c-lang-const c-decl-start-kwds))) - (c-lang-const c-decl-prefix-re))) + t (cond + ((and (c-lang-const c-decl-start-kwds) + (c-lang-const c-anchored-hash-define-no-parens)) + (concat (c-lang-const c-decl-prefix-re) + "\\|" (c-lang-const c-anchored-hash-define-no-parens) + "\\|" (c-make-keywords-re t (c-lang-const c-decl-start-kwds)))) + ((c-lang-const c-decl-start-kwds) + (concat (c-lang-const c-decl-prefix-re) + "\\|" (c-make-keywords-re t (c-lang-const c-decl-start-kwds)))) + ((c-lang-const c-anchored-hash-define-no-parens) + (concat (c-lang-const c-decl-prefix-re) + "\\|" (c-lang-const c-anchored-hash-define-no-parens))) + (t (c-lang-const c-decl-prefix-re)))) (c-lang-defvar c-decl-prefix-or-start-re (c-lang-const c-decl-prefix-or-start-re)) +(c-lang-defconst c-dposr-cpp-macro-depth + ;; The match number of `c-anchored-hash-define-no-parens''s first match + ;; within `c-decl-prefix-or-start-re', or nil if there is no such component. + t (if (c-lang-const c-anchored-hash-define-no-parens) + (1+ (regexp-opt-depth (c-lang-const c-decl-prefix-re))))) +(c-lang-defvar c-dposr-cpp-macro-depth (c-lang-const c-dposr-cpp-macro-depth)) + (c-lang-defconst c-cast-parens ;; List containing the paren characters that can open a cast, or nil in ;; languages without casts. -- cgit v1.2.1