From aa1a4cceca2d93d83c721ce83950230739073727 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Tue, 12 Mar 2019 18:33:31 +0000 Subject: [PATCH] Correct the indentation of CC Mode brace lists while preserving the indentation of nested C++ uniform initialization. * lisp/progmodes/cc-align.el (c-lineup-2nd-brace-entry-in-arglist) (c-lineup-class-decl-init-+, c-lineup-class-decl-init-after-brace): New indentation functions. * lisp/progmodes/cc-engine.el (c-forward-class-decl): New function. (c-do-declarators): New function, partially extracted from c-font-lock-declarators, which now calls the new function. (c-inside-bracelist-p): Amend the introductory comment. (c-add-stmt-syntax): Add code to prevent the spurious recognition of a 'defun-block-intro when a brace pair is used as an initializer. (c-evaluate-offset): No longer ignore vectors of length >= 2. (c-calc-offset): Refactor clumsily nested `if'/`or' into a cond form. * lisp/progmodes/cc-fonts.el (c-font-lock-declarators): Replace the bulk of this function by a call to the new c-forward-class-decl. * lisp/progmodes/cc-langs.el (c-type-decl-prefix-key): Recognize "~" as a type decl operator. * lisp/progmodes/cc-mode.el (c-fl-decl-start): While searching backward for a "}" at an EOD, deal with actually finding the end of a brace list. * doc/misc/cc-mode.texi (List Line-Up): document c-lineup-2nd-brace-entry-in-arglist, c-lineup-class-decl-init-+, and c-lineup-class-decl-init-after-brace. * lisp/progmodes/cc-styles.el (c-style-alist): In styles "gnu", "bsd", "stroustrup", "python", and "java", change the offset for brace-list-intro from the default value or c-lineup-arglist-intro-after-paren to a list beginning with the symbol first, followed by two of the new alignment functions, followed by +. * lisp/progmodes/cc-vars.el (c-offset-alist): Change the default value of brace-list-entry from c-lineup-under-anchor back to 0. --- doc/misc/cc-mode.texi | 125 ++++++++++++++++- lisp/progmodes/cc-align.el | 124 +++++++++++++++++ lisp/progmodes/cc-engine.el | 271 ++++++++++++++++++++++++++++-------- lisp/progmodes/cc-fonts.el | 143 +++++-------------- lisp/progmodes/cc-langs.el | 2 +- lisp/progmodes/cc-mode.el | 11 +- lisp/progmodes/cc-styles.el | 16 ++- lisp/progmodes/cc-vars.el | 2 +- 8 files changed, 524 insertions(+), 170 deletions(-) diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi index 0c77cc0ee61..170149eb550 100644 --- a/doc/misc/cc-mode.texi +++ b/doc/misc/cc-mode.texi @@ -5638,9 +5638,9 @@ any problems writing custom line-up functions for AWK mode. The calling convention for line-up functions is described fully in @ref{Custom Line-Up}. Roughly speaking, the return value is either an -offset itself (such as @code{+} or @code{[0]}) or it's @code{nil}, -meaning ``this function is inappropriate in this case; try a -different one''. @xref{c-offsets-alist}. +offset itself (such as @code{+} or @code{[0]}), another line-up +function, or it's @code{nil}, meaning ``this function is inappropriate +in this case - try a different one''. @xref{c-offsets-alist}. The subsections below describe all the standard line-up functions, categorized by the sort of token the lining-up centers around. For @@ -5995,6 +5995,125 @@ brace block. @comment ------------------------------------------------------------ +@defun c-lineup-2nd-brace-entry-in-arglist +@findex lineup-2nd-brace-entry-in-arglist (c-) +Line up the second entry of a brace block under the first, when the +first line is also contained in an arglist or an enclosing brace +@emph{on that line}. + +I.e. handle something like the following: + +@example +@group +set_line (line_t @{point_t@{0.4, 0.2@}, + point_t@{0.2, 0.5@}, @hereFn{brace-list-intro} + .....@}); + ^ enclosing parenthesis. +@end group +@end example + + +The middle line of that example will have a syntactic context with +three syntactic symbols, @code{arglist-cont-nonempty}, +@code{brace-list-intro}, and @code{brace-list-entry} (@pxref{Brace +List Symbols}). + +This function is intended for use in a list. If the construct being +analyzed isn't like the preceding, the function returns nil. +Otherwise it returns the function +@code{c-lineup-arglist-intro-after-paren}, which the caller then uses +to perform indentation. + +@workswith{} @code{brace-list-intro}. +@end defun + +@comment ------------------------------------------------------------ + +@defun c-lineup-class-decl-init-+ +@findex lineup-class-decl-init-+ (c-) +Line up the second entry of a class (etc.) initializer +@code{c-basic-offset} characters in from the identifier when: +@enumerate +@item +The type is a class, struct, union, etc. (but not an enum); +@item +There is a brace block in the type declaration, specifying it; and +@item +The first element of the initializer is on the same line as its +opening brace. +@end enumerate + +I.e. we have a construct like this: + +@example +@group +struct STR @{ + int i; float f; +@} str_1 = @{1, 1.7@}, + str_2 = @{2, + 3.1 @hereFn{brace-list-intro} + @}; + @sssTBasicOffset{} +@end group +@end example + + +Note that the syntactic context of the @code{brace-list-intro} line +also has a syntactic element with the symbol @code{brace-list-entry} +(@pxref{Brace List Symbols}). + +This function is intended for use in a list. If the above structure +isn't present, the function returns nil, allowing a different offset +specification to indent the line. + +@workswith{} @code{brace-list-intro}. +@end defun + +@comment ------------------------------------------------------------ + +@defun c-lineup-class-decl-init-after-brace +@findex lineup-class-decl-init-after-brace (c-) +Line up the second entry of a class (etc.) initializer after its +opening brace when: +@enumerate +@item +The type is a class, struct, union, etc. (but not an enum); +@item +There is a brace block in the type declaration, specifying it; and +@item +The first element of the initializer is on the same line as its +opening brace. +@end enumerate + +I.e. we have a construct like this: + +@example +@group +struct STR @{ + int i; float f; +@} str_1 = @{1, 1.7@}, + str_2 = @{2, + 3.1 @hereFn{brace-list-intro} + @}; +@end group +@end example + + +Note that the syntactic context of the @code{brace-list-intro} line +also has a syntactic element with the symbol @code{brace-list-entry} +(@pxref{Brace List Symbols}). Also note that this function works by +returning the symbol @code{c-lineup-arglist-intro-after-paren}, which +the caller then uses to perform the indentation. + +This function is intended for use in a list. If the above structure +isn't present, the function returns nil, allowing a different offset +specification to indent the line. + +@workswith{} @code{brace-list-intro}. +@end defun + +@comment ------------------------------------------------------------ + @defun c-lineup-multi-inher @findex lineup-multi-inher @r{(c-)} Line up the classes in C++ multiple inheritance clauses and member diff --git a/lisp/progmodes/cc-align.el b/lisp/progmodes/cc-align.el index 1f94bfd4fea..009f58ea586 100644 --- a/lisp/progmodes/cc-align.el +++ b/lisp/progmodes/cc-align.el @@ -1083,6 +1083,130 @@ arglist-cont." (vector (+ (current-column) c-basic-offset)))) (vector 0))))) +(defun c-lineup-2nd-brace-entry-in-arglist (langelem) + "Lineup the second entry of a brace block under the first, when the first +line is also contained in an arglist or an enclosing brace ON THAT LINE. + +I.e. handle something like the following: + + set_line (line_t {point_t{0.4, 0.2}, + point_t{0.2, 0.5}, <---- brace-list-intro + .....}); + ^ enclosing parenthesis. + +The middle line of that example will have a syntactic context +with three syntactic symbols, arglist-cont-nonempty, brace-list-intro, and +brace-list-entry. + +This function is intended for use in a list. If the construct +being analyzed isn't like the preceding, the function returns nil. +Otherwise it returns the function `c-lineup-arglist-intro-after-paren', which +the caller then uses to perform indentation. + +Works with brace-list-intro." + ;; brace-list-intro and brace-list-entry are both present for the second + ;; entry of the list when the first entry is on the same line as the opening + ;; brace. + (and (assq 'brace-list-intro c-syntactic-context) + (assq 'brace-list-entry c-syntactic-context) + (or (assq 'arglist-cont-nonempty c-syntactic-context) ; "(" earlier on + ; the line. + (save-excursion ; "{" earlier on the line + (goto-char (c-langelem-pos + (assq 'brace-list-intro c-syntactic-context))) + (and + (eq (c-backward-token-2 + 1 nil + (c-point 'bol (c-langelem-pos + (assq 'brace-list-entry + c-syntactic-context)))) + 0) + (eq (char-after) ?{)))) + 'c-lineup-arglist-intro-after-paren)) + +(defun c-lineup-class-decl-init-+ (langelem) + "Line up the second entry of a class (etc.) initializer c-basic-offset +characters in from the identifier when: +\(i) The type is a class, struct, union, etc. (but not an enum); +\(ii) There is a brace block in the type declaration, specifying it; and +\(iii) The first element of the initializer is on the same line as its opening +brace. + +I.e. we have a construct like this: + + struct STR { + int i; float f; + } str_1 = {1, 1.7}, + str_2 = {2, + 3.1 <---- brace-list-intro + }; + <--> <---- c-basic-offset + +Note that the syntactic context of the brace-list-intro line also has a +syntactic element with the symbol brace-list-entry. + +This function is intended for use in a list. If the above structure isn't +present, this function returns nil, allowing a different offset specification +to indent the line. + +Works with: brace-list-intro." + (and (assq 'brace-list-intro c-syntactic-context) + (assq 'brace-list-entry c-syntactic-context) + (let ((init-pos (c-point 'boi (c-langelem-pos + (assq 'brace-list-entry + c-syntactic-context)))) + ) + (save-excursion + (goto-char (c-langelem-pos (assq 'brace-list-intro + c-syntactic-context))) + (and + (c-forward-class-decl) + (not (c-do-declarators init-pos t nil nil nil)) + (eq (point) init-pos) + (vector (+ (current-column) c-basic-offset))))))) + +(defun c-lineup-class-decl-init-after-brace (langelem) + "Line up the second entry of a class (etc.) initializer after its opening +brace when: +\(i) The type is a class, struct, union, etc. (but not an enum); +\(ii) There is a brace block in the type declaration, specifying it; and +\(iii) The first element of the initializer is on the same line as its opening +brace. + +I.e. we have a construct like this: + + struct STR { + int i; float f; + } str_1 = {1, 1.7}, + str_2 = {2, + 3.1 <---- brace-list-intro + }; + +Note that the syntactic context of the brace-list-intro line also has a +syntactic element with the symbol brace-list-entry. Also note that this +function works by returning the symbol `c-lineup-arglist-intro-after-paren', +which the caller then uses to perform the indentation. + +This function is intended for use in a list. If the above structure isn't +present, this function returns nil, allowing a different offset specification +to indent the line. + +Works with: brace-list-intro." + (and (assq 'brace-list-intro c-syntactic-context) + (assq 'brace-list-entry c-syntactic-context) + (let ((init-pos (c-point 'boi (c-langelem-pos + (assq 'brace-list-entry + c-syntactic-context)))) + ) + (save-excursion + (goto-char (c-langelem-pos (assq 'brace-list-intro + c-syntactic-context))) + (and + (c-forward-class-decl) + (not (c-do-declarators init-pos t nil nil nil)) + (eq (point) init-pos) + 'c-lineup-arglist-intro-after-paren))))) + (defun c-lineup-cpp-define (_langelem) "Line up macro continuation lines according to the indentation of the construct preceding the macro. E.g.: diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 301d07c9c9c..fd669280994 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -8040,49 +8040,28 @@ comment at the start of cc-engine.el for more info." (or res (goto-char here)) res)) +(defun c-forward-class-decl () + "From the beginning of a struct/union, etc. move forward to +after the brace block which defines it, leaving point at the +start of the next token and returning point. On failure leave +point unchanged and return nil." + (let ((here (point))) + (if + (and + (looking-at c-class-key) + (eq (c-forward-token-2) 0) + (c-on-identifier) + (eq (c-forward-token-2) 0) + (eq (char-after) ?{) + (c-go-list-forward)) + (progn + (c-forward-syntactic-ws) + (point)) + (goto-char here) + nil))) ;; Handling of large scale constructs like statements and declarations. -;; Macro used inside `c-forward-decl-or-cast-1'. It ought to be a -;; defsubst or perhaps even a defun, but it contains lots of free -;; variables that refer to things inside `c-forward-decl-or-cast-1'. -(defmacro c-fdoc-shift-type-backward (&optional short) - ;; `c-forward-decl-or-cast-1' can consume an arbitrary length list - ;; of types when parsing a declaration, which means that it - ;; sometimes consumes the identifier in the declaration as a type. - ;; This is used to "backtrack" and make the last type be treated as - ;; an identifier instead. - `(progn - ,(unless short - ;; These identifiers are bound only in the inner let. - '(setq identifier-type at-type - identifier-start type-start - got-parens nil - got-identifier t - got-suffix t - got-suffix-after-parens id-start - paren-depth 0)) - - (if (setq at-type (if (eq backup-at-type 'prefix) - t - backup-at-type)) - (setq type-start backup-type-start - id-start backup-id-start) - (setq type-start start-pos - id-start start-pos)) - - ;; When these flags already are set we've found specifiers that - ;; unconditionally signal these attributes - backtracking doesn't - ;; change that. So keep them set in that case. - (or at-type-decl - (setq at-type-decl backup-at-type-decl)) - (or maybe-typeless - (setq maybe-typeless backup-maybe-typeless)) - - ,(unless short - ;; This identifier is bound only in the inner let. - '(setq start id-start)))) - (defun c-forward-declarator (&optional limit accept-anon) ;; Assuming point is at the start of a declarator, move forward over it, ;; leaving point at the next token after it (e.g. a ) or a ; or a ,). @@ -8235,6 +8214,176 @@ comment at the start of cc-engine.el for more info." (goto-char here) nil))) +(defun c-do-declarators + (cdd-limit cdd-list cdd-not-top cdd-comma-prop cdd-function) + "Assuming point is at the start of a comma separated list of declarators, +apply CDD-FUNCTION to each declarator (when CDD-LIST is non-nil) or just the +first declarator (when CDD-LIST is nil). When CDD-FUNCTION is nil, no +function is applied. + +CDD-FUNCTION is supplied with 6 arguments: +0. The start position of the declarator's identifier; +1. The end position of this identifier; +\[Note: if there is no identifier, as in int (*);, both of these are nil.] +2. The position of the next token after the declarator (CLARIFY!!!). +3. CDD-NOT-TOP; +4. Non-nil if the identifier is of a function. +5. When there is an initialization following the declarator (such as \"= +....\" or \"( ....\".), the character which introduces this initialization, +otherwise nil. + +Additionally, if CDD-COMMA-PROP is non-nil, mark the separating commas with +this value of the c-type property, when CDD-LIST is non-nil. + +Stop at or before CDD-LIMIT (which may NOT be nil). + +If CDD-NOT-TOP is non-nil, we are not at the top-level (\"top-level\" includes +being directly inside a class or namespace, etc.). + +Return non-nil if we've reached the token after the last declarator (often a +semicolon, or a comma when CDD-LIST is nil); otherwise (when we hit CDD-LIMIT, +or fail otherwise) return nil, leaving point at the beginning of the putative +declarator that could not be processed. + +This function might do hidden buffer changes." + ;; N.B.: We use the "cdd-" prefix in this routine to try to prevent + ;; confusion with possible reference to common variable names from within + ;; CDD-FUNCTION. + (let + ((cdd-pos (point)) cdd-next-pos cdd-id-start cdd-id-end + cdd-decl-res cdd-got-func cdd-got-type cdd-got-init + c-last-identifier-range cdd-exhausted) + + ;; The following `while' applies `cdd-function' to a single declarator id + ;; each time round. It loops only when CDD-LIST is non-nil. + (while + (and (not cdd-exhausted) + (setq cdd-decl-res (c-forward-declarator cdd-limit))) + (setq cdd-next-pos (point) + cdd-id-start (car cdd-decl-res) + cdd-id-end (cadr cdd-decl-res) + cdd-got-func (and (eq (char-after) ?\() + (or (not (c-major-mode-is 'c++-mode)) + (not cdd-not-top) + (car (cddr (cddr cdd-decl-res))) ; Id is in + ; parens, etc. + (save-excursion + (forward-char) + (c-forward-syntactic-ws) + (looking-at "[*&]"))) + (not (car (cddr cdd-decl-res))) + (or (not (c-major-mode-is 'c++-mode)) + (save-excursion + (let (c-last-identifier-range) + (forward-char) + (c-forward-syntactic-ws) + (catch 'is-function + (while + (progn + (if (eq (char-after) ?\)) + (throw 'is-function t)) + (setq cdd-got-type (c-forward-type)) + (cond + ((null cdd-got-type) + (throw 'is-function nil)) + ((not (eq cdd-got-type 'maybe)) + (throw 'is-function t))) + (c-forward-declarator nil t) + (eq (char-after) ?,)) + (forward-char) + (c-forward-syntactic-ws)) + t))))) + cdd-got-init (and (cadr (cddr cdd-decl-res)) + (char-after))) + + ;; Jump past any initializer or function prototype to see if + ;; there's a ',' to continue at. + (cond (cdd-got-func + ;; Skip a parenthesized initializer (C++) or a function + ;; prototype. + (if (c-go-list-forward (point) cdd-limit) ; over the parameter list. + (c-forward-syntactic-ws cdd-limit) + (setq cdd-exhausted t))) ; unbalanced parens + + (cdd-got-init ; "=" sign OR opening "(", "[", or "{" + ;; Skip an initializer expression. If we're at a '=' + ;; then accept a brace list directly after it to cope + ;; with array initializers. Otherwise stop at braces + ;; to avoid going past full function and class blocks. + (if (and (if (and (eq cdd-got-init ?=) + (= (c-forward-token-2 1 nil cdd-limit) 0) + (looking-at "{")) + (c-go-list-forward (point) cdd-limit) + t) + ;; FIXME: Should look for c-decl-end markers here; + ;; we might go far into the following declarations + ;; in e.g. ObjC mode (see e.g. methods-4.m). + (c-syntactic-re-search-forward "[;,{]" cdd-limit 'move t)) + (backward-char) + (setq cdd-exhausted t) + )) + + (t (c-forward-syntactic-ws cdd-limit))) + + (if cdd-function + (funcall cdd-function cdd-id-start cdd-id-end cdd-next-pos + cdd-not-top cdd-got-func cdd-got-init)) + + ;; If a ',' is found we set cdd-pos to the next declarator and iterate. + (if (and cdd-list (< (point) cdd-limit) (looking-at ",")) + (progn + (when cdd-comma-prop + (c-put-char-property (point) 'c-type cdd-comma-prop)) + (forward-char) + (c-forward-syntactic-ws cdd-limit) + (setq cdd-pos (point))) + (setq cdd-exhausted t))) + + (if (> (point) cdd-pos) + t + (goto-char cdd-pos) + nil))) + +;; Macro used inside `c-forward-decl-or-cast-1'. It ought to be a +;; defsubst or perhaps even a defun, but it contains lots of free +;; variables that refer to things inside `c-forward-decl-or-cast-1'. +(defmacro c-fdoc-shift-type-backward (&optional short) + ;; `c-forward-decl-or-cast-1' can consume an arbitrary length list + ;; of types when parsing a declaration, which means that it + ;; sometimes consumes the identifier in the declaration as a type. + ;; This is used to "backtrack" and make the last type be treated as + ;; an identifier instead. + `(progn + ,(unless short + ;; These identifiers are bound only in the inner let. + '(setq identifier-type at-type + identifier-start type-start + got-parens nil + got-identifier t + got-suffix t + got-suffix-after-parens id-start + paren-depth 0)) + + (if (setq at-type (if (eq backup-at-type 'prefix) + t + backup-at-type)) + (setq type-start backup-type-start + id-start backup-id-start) + (setq type-start start-pos + id-start start-pos)) + + ;; When these flags already are set we've found specifiers that + ;; unconditionally signal these attributes - backtracking doesn't + ;; change that. So keep them set in that case. + (or at-type-decl + (setq at-type-decl backup-at-type-decl)) + (or maybe-typeless + (setq maybe-typeless backup-maybe-typeless)) + + ,(unless short + ;; This identifier is bound only in the inner let. + '(setq start id-start)))) + (defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end) ;; Move forward over a declaration or a cast if at the start of one. ;; The point is assumed to be at the start of some token. Nil is @@ -10727,12 +10876,17 @@ comment at the start of cc-engine.el for more info." ))) (defun c-inside-bracelist-p (containing-sexp paren-state accept-in-paren) - ;; return the buffer position of the beginning of the brace list - ;; statement if we're inside a brace list, otherwise return nil. - ;; CONTAINING-SEXP is the buffer pos of the innermost containing - ;; paren. PAREN-STATE is the remainder of the state of enclosing - ;; braces. ACCEPT-IN-PAREN is non-nil iff we will accept as a brace - ;; list a brace directly enclosed in a parenthesis. + ;; return the buffer position of the beginning of the brace list statement + ;; if CONTAINING-SEXP is inside a brace list, otherwise return nil. + ;; + ;; CONTAINING-SEXP is the buffer pos of the innermost containing paren. NO + ;; IT ISN'T!!! [This function is badly designed, and probably needs + ;; reformulating without its first argument, and the critical position being + ;; at point.] + ;; + ;; PAREN-STATE is the remainder of the state of enclosing braces. + ;; ACCEPT-IN-PAREN is non-nil iff we will accept as a brace list a brace + ;; directly enclosed in a parenthesis. ;; ;; The "brace list" here is recognized solely by its context, not by ;; its contents. @@ -10852,7 +11006,8 @@ comment at the start of cc-engine.el for more info." (defun c-looking-at-statement-block () ;; Point is at an opening brace. If this is a statement block (i.e. the ;; elements in the block are terminated by semicolons, or the block is - ;; empty, or the block contains a keyword) return t. Otherwise, return nil. + ;; empty, or the block contains a keyword) return non-nil. Otherwise, + ;; return nil. (let ((here (point))) (prog1 (if (c-go-list-forward) @@ -11356,7 +11511,7 @@ comment at the start of cc-engine.el for more info." (if (and (eq step-type 'same) (/= paren-pos (point))) - (let (inexpr) + (let (inexpr bspec) (cond ((save-excursion (goto-char paren-pos) @@ -11378,6 +11533,13 @@ comment at the start of cc-engine.el for more info." (c-looking-at-statement-block)) (c-add-syntax 'defun-block-intro nil) (c-add-syntax 'brace-list-intro nil))) + ((save-excursion + (goto-char paren-pos) + (setq bspec (c-looking-at-or-maybe-in-bracelist + containing-sexp containing-sexp)) + (and (consp bspec) + (eq (cdr bspec) 'in-paren))) + (c-add-syntax 'brace-list-intro (car bspec))) (t (c-add-syntax 'defun-block-intro nil)))) (c-add-syntax 'statement-block-intro nil))) @@ -13242,7 +13404,7 @@ Cannot combine absolute offsets %S and %S in `add' method" nil)))) (if (or (null res) (integerp res) - (and (vectorp res) (= (length res) 1) (integerp (aref res 0)))) + (and (vectorp res) (>= (length res) 1) (integerp (aref res 0)))) res (c-benign-error "Error evaluating offset %S for %s: Got invalid value %S" offset symbol res) @@ -13265,12 +13427,11 @@ Cannot combine absolute offsets %S and %S in `add' method" (if c-strict-syntax-p (c-benign-error "No offset found for syntactic symbol %s" symbol)) (setq offset 0)) - (if (vectorp offset) - offset - (or (and (numberp offset) offset) - (and (symbolp offset) (symbol-value offset)) - 0)) - )) + (cond + ((or (vectorp offset) (numberp offset)) + offset) + ((and (symbolp offset) (symbol-value offset))) + (t 0)))) (defun c-get-offset (langelem) ;; This is a compatibility wrapper for `c-calc-offset' in case diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index 0588032fdbe..0b41eff1577 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1032,114 +1032,41 @@ casts and declarations are fontified. Used on level 2 and higher." ;;(message "c-font-lock-declarators from %s to %s" (point) limit) (c-fontify-types-and-refs - ((pos (point)) next-pos id-start - decl-res - id-face got-type got-init - c-last-identifier-range - (separator-prop (if types 'c-decl-type-start 'c-decl-id-start))) - - ;; The following `while' fontifies a single declarator id each time round. - ;; It loops only when LIST is non-nil. - (while - (and pos (setq decl-res (c-forward-declarator))) - (setq next-pos (point) - id-start (car decl-res) - id-face (if (and (eq (char-after) ?\() - (or (not (c-major-mode-is 'c++-mode)) - (not not-top) - (car (cddr (cddr decl-res))) ; Id is in - ; parens, etc. - (save-excursion - (forward-char) - (c-forward-syntactic-ws) - (looking-at "[*&]"))) - (not (car (cddr decl-res))) - (or (not (c-major-mode-is 'c++-mode)) - (save-excursion - (let (c-last-identifier-range) - (forward-char) - (c-forward-syntactic-ws) - (catch 'is-function - (while - (progn - (if (eq (char-after) ?\)) - (throw 'is-function t)) - (setq got-type (c-forward-type)) - (cond - ((null got-type) - (throw 'is-function nil)) - ((not (eq got-type 'maybe)) - (throw 'is-function t))) - (c-forward-declarator nil t) - (eq (char-after) ?,)) - (forward-char) - (c-forward-syntactic-ws)) - t))))) - 'font-lock-function-name-face - 'font-lock-variable-name-face) - got-init (and (cadr (cddr decl-res)) ; got-init - (char-after))) - - (if types - ;; Register and fontify the identifier as a type. - (let ((c-promote-possible-types t)) - (goto-char id-start) - (c-forward-type)) - ;; Fontify the last symbol in the identifier if it isn't fontified - ;; already. The check is necessary only in certain cases where this - ;; function is used "sloppily", e.g. in `c-simple-decl-matchers'. - (when (and c-last-identifier-range - (not (get-text-property (car c-last-identifier-range) - 'face))) - (c-put-font-lock-face (car c-last-identifier-range) - (cdr c-last-identifier-range) - id-face))) - - (goto-char next-pos) - (setq pos nil) ; So as to terminate the enclosing `while' form. - (if (and template-class - (eq got-init ?=) ; C++ ""? - (c-forward-token-2 1 nil limit) ; Over "=" - (let ((c-promote-possible-types t)) - (c-forward-type t))) ; Over "Y" - (setq list nil)) ; Shouldn't be needed. We can't have a list, here. - - (when list - ;; Jump past any initializer or function prototype to see if - ;; there's a ',' to continue at. - (cond ((eq id-face 'font-lock-function-name-face) - ;; Skip a parenthesized initializer (C++) or a function - ;; prototype. - (if (c-safe (c-forward-sexp 1) t) ; over the parameter list. - (c-forward-syntactic-ws limit) - (goto-char limit))) ; unbalanced parens - - (got-init ; "=" sign OR opening "(", "[", or "{" - ;; Skip an initializer expression. If we're at a '=' - ;; then accept a brace list directly after it to cope - ;; with array initializers. Otherwise stop at braces - ;; to avoid going past full function and class blocks. - (and (if (and (eq got-init ?=) - (= (c-forward-token-2 1 nil limit) 0) - (looking-at "{")) - (c-safe (c-forward-sexp) t) ; over { .... } - t) - (< (point) limit) - ;; FIXME: Should look for c-decl-end markers here; - ;; we might go far into the following declarations - ;; in e.g. ObjC mode (see e.g. methods-4.m). - (c-syntactic-re-search-forward "[;,{]" limit 'move t) - (backward-char))) - - (t (c-forward-syntactic-ws limit))) - - ;; If a ',' is found we set pos to the next declarator and iterate. - (when (and (< (point) limit) (looking-at ",")) - (c-put-char-property (point) 'c-type separator-prop) - (forward-char) - (c-forward-syntactic-ws limit) - (setq pos (point)))))) ; acts to make the `while' form continue. - nil) + () + (c-do-declarators + limit list not-top + (if types 'c-decl-type-start 'c-decl-id-start) + (lambda (id-start id-end end-pos not-top is-function init-char) + (if types + ;; Register and fontify the identifier as a type. + (let ((c-promote-possible-types t)) + (goto-char id-start) + (c-forward-type)) + ;; The following doesn't work properly (yet, 2018-09-22). + ;; (c-put-font-lock-face id-start id-end + ;; (if is-function + ;; 'font-lock-function-name-face + ;; 'font-lock-variable-name-face)) + (when (and c-last-identifier-range + (not (get-text-property (car c-last-identifier-range) + 'face))) + ;; We use `c-last-identifier-range' rather than `id-start' and + ;; `id-end', since the latter two can be erroneous. E.g. in + ;; "~Foo", `id-start' is at the tilde. This is a bug in + ;; `c-forward-declarator'. + (c-put-font-lock-face (car c-last-identifier-range) + (cdr c-last-identifier-range) + (if is-function + 'font-lock-function-name-face + 'font-lock-variable-name-face)))) + (and template-class + (eq init-char ?=) ; C++ ""? + (progn + (goto-char end-pos) + (c-forward-token-2 1 nil limit) ; Over "=" + (let ((c-promote-possible-types t)) + (c-forward-type t)))))) + nil)) (defun c-get-fontification-context (match-pos not-front-decl &optional toplev) ;; Return a cons (CONTEXT . RESTRICTED-<>-ARGLISTS) for MATCH-POS. diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 53342713b4a..7cc8029e0a3 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -3258,7 +3258,7 @@ Identifier syntax is in effect when this is matched \(see "\\|" "\\.\\.\\." "\\|" - "[*(&]" + "[*(&~]" "\\|" (c-lang-const c-type-decl-prefix-key) "\\|" diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 4e63bd9144b..8343978fc38 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -1803,7 +1803,16 @@ Note that this is a strict tail, so won't match, e.g. \"0x....\".") ;; Go to a less nested declaration each time round this loop. (and (setq old-pos (point)) - (c-syntactic-skip-backward "^;{}" bod-lim t) + (let (pseudo) + (while + (progn + (c-syntactic-skip-backward "^;{}" bod-lim t) + (and (eq (char-before) ?}) + (save-excursion + (backward-char) + (setq pseudo (c-cheap-inside-bracelist-p (c-parse-state)))))) + (goto-char pseudo)) + t) (> (point) bod-lim) (progn (c-forward-syntactic-ws) ;; Have we got stuck in a comment at EOB? diff --git a/lisp/progmodes/cc-styles.el b/lisp/progmodes/cc-styles.el index d2c41008711..92ea67128f4 100644 --- a/lisp/progmodes/cc-styles.el +++ b/lisp/progmodes/cc-styles.el @@ -68,7 +68,9 @@ (arglist-close . c-lineup-arglist) (inline-open . 0) (brace-list-open . +) - (brace-list-intro . c-lineup-arglist-intro-after-paren) + (brace-list-intro . (first + c-lineup-2nd-brace-entry-in-arglist + c-lineup-class-decl-init-+ +)) (topmost-intro-cont . (first c-lineup-topmost-intro-cont c-lineup-gnu-DEFUN-intro-cont)))) @@ -95,6 +97,9 @@ (label . 0) (statement-cont . +) (inline-open . 0) + (brace-list-intro . (first + c-lineup-2nd-brace-entry-in-arglist + c-lineup-class-decl-init-+ +)) (inexpr-class . 0)))) ("stroustrup" @@ -104,6 +109,9 @@ (substatement-open . 0) (substatement-label . 0) (label . 0) + (brace-list-intro . (first + c-lineup-2nd-brace-entry-in-arglist + c-lineup-class-decl-init-+ +)) (statement-cont . +)))) ("whitesmith" @@ -194,6 +202,9 @@ (c-offsets-alist . ((substatement-open . 0) (inextern-lang . 0) (arglist-intro . +) + (brace-list-intro . (first + c-lineup-2nd-brace-entry-in-arglist + c-lineup-class-decl-init-+ +)) (knr-argdecl-intro . +))) (c-hanging-braces-alist . ((brace-list-open) (brace-list-intro) @@ -219,6 +230,9 @@ (statement-cont . +) (arglist-intro . c-lineup-arglist-intro-after-paren) (arglist-close . c-lineup-arglist) + (brace-list-intro . (first + c-lineup-2nd-brace-entry-in-arglist + c-lineup-class-decl-init-+ +)) (access-label . 0) (inher-cont . c-lineup-java-inher) (func-decl-cont . c-lineup-java-throws)))) diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 89534882672..6e8acd4c0dd 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -1115,7 +1115,7 @@ can always override the use of `c-default-style' by making calls to ;; Anchor pos: At the brace list decl start(*). (brace-list-intro . +) ;; Anchor pos: At the brace list decl start(*). - (brace-list-entry . c-lineup-under-anchor) + (brace-list-entry . 0) ;; Anchor pos: At the first non-ws char after the open paren if ;; the first token is on the same line, otherwise boi at that ;; token. -- 2.39.5