CC Mode: Fix various minor indentation bugs

As part of this, introduce a second anchor point to the
syntactic symbols brace-list-intro and enum-intro, the position
of the opening brace.

* lisp/progmodes/cc-align.el
(c-lineup-item-after-paren-at-boi): New function.

* /lisp/progmodes/cc-engine.el
(c-foreign-truncate-lit-pos-cache)
(c-foreign-init-lit-pos-cache): Use
c-truncate-lit-pos/state-cache in place of an older function.
(c-no-bracelist-cache): Update its definition to exclude
conses.
(c-strip-conses): New function.
(c-inside-bracelist-p): Use c-strip-conses.
(c-add-stmt-syntax): In the "go out a block" loop, go out of a
brace at BOI when there's non-whitespace text after it.
Refactor an `if' form containing a cond form into a cond form.
Add the new second second anchor point into syntactic contexts
with brace-list-intro and enum-intro.  Anchor brace-list-close
and enum-close elements on the individual declarations in
struct, etc., variable declarations.
(c-guess-basic-syntax, CASE 20): Use the new constraint-cont
syntactic symbol.
(c-guess-basic-syntax, CASE 9B): Anchor brace-list-close and
enum-close elements on the individual declarations in struct,
etc., variable declarations.
(c-guess-basic-syntax, CASEs 9C, 9D): Add the new second anchor
point into brace-list-intro and enum-intro syntactic contexts.

* lisp/progmodes/cc-mode.el (c-locate-first-punctuation-prop):
New function.
(c-depropertize-CPP): Use c-locate-first-punctuation-prop.

* lisp/progmodes/cc-vars.el (c-offsets-alist): Amend the
entries for constraint-cont, brace-list-intro, and enum-intro,
using c-lineup-item-after-paren-at-boi.

* doc/misc/cc-mode.texi (List Line-Up): Add a description of
c-lineup-item-after-paren-at-boi.
This commit is contained in:
Alan Mackenzie 2024-12-31 18:39:57 +00:00
parent 2f1052d9b0
commit 643e32340d
5 changed files with 189 additions and 65 deletions

View file

@ -6192,6 +6192,33 @@ to perform indentation.
@comment ------------------------------------------------------------
@defun c-lineup-item-after-paren-at-boi
@findex lineup-item-after-paren-at-boi (c-)
Line up under the first entry on the same line as an open parenthesis
when that parenthesis is the lefmost non-space character in its line.
For example:
@example
@group
template <typename T>
requires
( requires (T t) @{ ++t; @}
&& Baz<T>) @hereFn{constraint-cont}
int foo();
@end group
@end example
This function is intended for use in a list. If the construct being
analyzed doesn't conform to the above description, the function
returns nil. Otherwise it returns a vector containing the indentation.
@workswith{} @code{brace-list-intro}, @code{enum-intro},
@code{constraint-cont}.
@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

View file

@ -314,6 +314,30 @@ statement-block-intro, statement-case-intro, arglist-intro."
(if (eolp) (skip-chars-backward " \t"))
(vector (current-column))))
(defun c-lineup-item-after-paren-at-boi (_langelem)
"Line up a *-cont line to just after the surrounding open paren at boi.
\"paren\" here can also mean \"brace\", etc. We line up under the first
non-whitespace text after the paren. If there is no such paren, or no
such text, return nil, allowing another function to handle the
construct.
Works with: brace-list-intro, enum-intro, constraint-cont."
(save-excursion
(beginning-of-line)
(and
(if (c-langelem-2nd-pos c-syntactic-element)
;; brace-list-intro, enum-intro.
(progn (goto-char (c-langelem-2nd-pos c-syntactic-element))
t)
;; constraint-cont.
(c-go-up-list-backward nil (c-langelem-pos c-syntactic-element)))
(eq (point) (c-point 'boi))
(looking-at "\\s(")
(progn (forward-char)
(c-forward-syntactic-ws (c-point 'eol))
(unless (eolp)
(vector (current-column)))))))
(defun c-lineup-arglist-close-under-paren (langelem)
"Line up a line under the enclosing open paren.
Normally used to line up a closing paren in the same column as its

View file

@ -3233,7 +3233,7 @@ This function should be added to the `before-change-functions'
hook by major modes that use CC Mode's filling functionality
without initializing CC Mode. Currently (2020-06) these are
`js-mode' and `mhtml-mode'."
(c-truncate-lit-pos-cache beg))
(c-truncate-lit-pos/state-cache beg))
(defun c-foreign-init-lit-pos-cache ()
"Initialize CC Mode's literal cache.
@ -3242,7 +3242,7 @@ This function should be called from the mode functions of major
modes which use CC Mode's filling functionality without
initializing CC Mode. Currently (2020-06) these are `js-mode' and
`mhtml-mode'."
(c-truncate-lit-pos-cache 1))
(c-truncate-lit-pos/state-cache 1))
;; A system for finding noteworthy parens before the point.
@ -13365,12 +13365,21 @@ comment at the start of cc-engine.el for more info."
(t t)))) ;; The caller can go up one level.
))))
;; A list of the form returned by `c-parse-state'. Each opening brace in it
;; is not the brace of a brace list. Any cons items in it are ignored, and
;; are also unreliable.
;; A list of the form returned by `c-parse-state', but without conses. Each
;; opening brace in it is not the brace of a brace list.
(defvar c-no-bracelist-cache nil)
(make-variable-buffer-local 'c-no-bracelist-cache)
(defun c-strip-conses (liszt)
;; Make a copy of the list LISZT, removing conses from the copy. Return the
;; result.
(let ((ptr liszt) new)
(while ptr
(if (atom (car ptr))
(push (car ptr) new))
(setq ptr (cdr ptr)))
(nreverse new)))
(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 CONTAINING-SEXP is inside a brace list, otherwise return nil.
@ -13433,13 +13442,13 @@ comment at the start of cc-engine.el for more info."
(not (memq next-containing c-no-bracelist-cache)))
(setq next-containing (c-pull-open-brace paren-state)))
(setq c-no-bracelist-cache
(nconc whole-paren-state
(nconc (c-strip-conses whole-paren-state)
(and next-containing (list next-containing))
paren-state))
nil)
((not (memq containing-sexp c-no-bracelist-cache))
;; Update `c-no-bracelist-cache'
(setq c-no-bracelist-cache (copy-tree whole-paren-state))
(setq c-no-bracelist-cache (c-strip-conses whole-paren-state))
nil)))))
(defun c-looking-at-special-brace-list ()
@ -14067,6 +14076,7 @@ comment at the start of cc-engine.el for more info."
(let ((syntax-last c-syntactic-context)
(boi (c-point 'boi))
(anchor-boi (c-point 'boi))
(anchor-point-2 containing-sexp)
;; Set when we're on a label, so that we don't stop there.
;; FIXME: To be complete we should check if we're on a label
;; now at the start.
@ -14078,17 +14088,24 @@ comment at the start of cc-engine.el for more info."
(point) nil)
syntax-extra-args)
;; Loop while we have to back out of containing blocks.
;; Each time round the following loop, back out of the containing block.
;; Do this unless `fixed-anchor' is non-nil and `containing-sexp' is at
;; or before the BOI of the anchor position. Carry on until the inner
;; `while' loop fails to back up to `containing-sexp', or we reach the
;; top level, or `containing-sexp' is before the initial anchor point.
(while
(and
(catch 'back-up-block
;; Loop while we have to back up statements.
;; Each time round the following loop, back up a single
;; statement until we reach a BOS at BOI, or `containing-sexp',
;; or any previous statement when `stop-at-boi-only' is nil.
;; More or less. Read the source for full details. ;-(
(while (or (/= (point) boi)
on-label
(looking-at c-comment-start-regexp))
;; Skip past any comments that stands between the
;; Skip past any comments that stand between the
;; statement start and boi.
(let ((savepos (point)))
(while (and (/= savepos boi)
@ -14146,7 +14163,11 @@ comment at the start of cc-engine.el for more info."
containing-sexp
(or (null fixed-anchor)
(> containing-sexp anchor-boi)))
(> containing-sexp anchor-boi)
(save-excursion
(goto-char (1+ containing-sexp))
(c-forward-syntactic-ws (c-point 'eol))
(< (point) (c-point 'eol)))))
;; Now we have to go out of this block.
(goto-char containing-sexp)
@ -14168,7 +14189,7 @@ comment at the start of cc-engine.el for more info."
;; from and add the right syntactic element for it.
(let ((paren-pos (point))
(paren-char (char-after))
step-type)
step-type anchor-point)
(if (eq paren-char ?\()
;; Stepped out of a parenthesis block, so we're in an
@ -14199,45 +14220,62 @@ comment at the start of cc-engine.el for more info."
on-label nil))
;; Stepped out of a brace block.
(save-excursion
(if (and (zerop (c-backward-token-2))
(looking-at "=\\([^=]\\|$\\)")
(zerop (c-backward-token-2))
(looking-at c-symbol-key)
(not (looking-at c-keywords-regexp)))
(setq anchor-point (point))))
(if anchor-point
(progn (goto-char anchor-point)
(setq step-type 'same
on-label nil))
(setq step-type (c-beginning-of-statement-1 containing-sexp)
on-label (eq step-type 'label))
on-label (eq step-type 'label)))
(if (and (eq step-type 'same)
(/= paren-pos (point)))
(let (inexpr bspec)
(cond
((save-excursion
(let (inexpr bspec)
(cond
((or (not (eq step-type 'same))
(eq paren-pos (point)))
(if (and (eq paren-pos (point))
(c-inside-bracelist-p paren-pos paren-state nil))
(c-add-syntax 'brace-list-intro nil anchor-point-2)
(c-add-syntax 'statement-block-intro nil)))
((save-excursion
(goto-char paren-pos)
(setq inexpr (c-looking-at-inexpr-block
(c-safe-position containing-sexp paren-state)
containing-sexp)))
(c-add-syntax (if (eq (car inexpr) 'inlambda)
'defun-block-intro
'statement-block-intro)
nil))
((looking-at c-other-decl-block-key)
(c-add-syntax
(cdr (assoc (match-string 1)
c-other-decl-block-key-in-symbols-alist))
(max (c-point 'boi paren-pos) (point))))
((c-at-enum-brace paren-pos)
(c-add-syntax 'enum-intro nil anchor-point-2))
((c-inside-bracelist-p paren-pos paren-state nil)
(if (save-excursion
(goto-char paren-pos)
(setq inexpr (c-looking-at-inexpr-block
(c-safe-position containing-sexp paren-state)
containing-sexp)))
(c-add-syntax (if (eq (car inexpr) 'inlambda)
'defun-block-intro
'statement-block-intro)
nil))
((looking-at c-other-decl-block-key)
(c-add-syntax
(cdr (assoc (match-string 1)
c-other-decl-block-key-in-symbols-alist))
(max (c-point 'boi paren-pos) (point))))
((c-at-enum-brace paren-pos)
(c-add-syntax 'enum-intro nil))
((c-inside-bracelist-p paren-pos paren-state nil)
(if (save-excursion
(goto-char paren-pos)
(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-looking-at-statement-block))
(c-add-syntax 'defun-block-intro nil)
(c-add-syntax 'brace-list-intro nil anchor-point-2)))
((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)
anchor-point-2))
(t (c-add-syntax 'defun-block-intro nil))))
(c-add-syntax 'statement-block-intro nil)))
(setq anchor-point-2 containing-sexp))
(if (= paren-pos boi)
;; Always done if the open brace was at boi. The
@ -15489,9 +15527,13 @@ comment at the start of cc-engine.el for more info."
(not (eq (cdr tmp) 'expression))
(setq placeholder (car tmp)))
(c-add-syntax
(if (eq char-after-ip ?{)
'substatement-open
'substatement)
(cond
((and (eq (char-after containing-sexp) ?\()
(> containing-sexp placeholder))
'constraint-cont)
((eq char-after-ip ?{)
'substatement-open)
(t 'substatement))
(c-point 'boi placeholder)))
;; ((Old) CASE 6 has been removed.)
@ -15761,7 +15803,17 @@ comment at the start of cc-engine.el for more info."
(c-determine-limit 1000))
(point)))
(c-most-enclosing-brace state-cache (point))))
(c-beginning-of-statement-1 lim nil nil t)
(save-excursion
(setq placeholder
(and (zerop (c-backward-token-2))
(looking-at "=\\([^=]\\|$\\)")
(zerop (c-backward-token-2))
(looking-at c-symbol-key)
(not (looking-at c-keywords-regexp))
(point))))
(if placeholder
(goto-char placeholder)
(c-beginning-of-statement-1 lim nil nil t))
(c-add-stmt-syntax (if enum-pos 'enum-close 'brace-list-close)
nil t lim paren-state)))
@ -15790,7 +15842,7 @@ comment at the start of cc-engine.el for more info."
(goto-char containing-sexp))
(if (eq (point) (c-point 'boi))
(c-add-syntax (if enum-pos 'enum-intro 'brace-list-intro)
(point))
(point) containing-sexp)
(setq lim (or (save-excursion
(and
(c-back-over-member-initializers
@ -15799,20 +15851,25 @@ comment at the start of cc-engine.el for more info."
(c-most-enclosing-brace state-cache (point))))
(c-beginning-of-statement-1 lim nil nil t)
(c-add-stmt-syntax (if enum-pos 'enum-intro 'brace-list-intro)
nil t lim paren-state)))
(list containing-sexp)
t lim paren-state)))
;; CASE 9D: this is just a later brace-list-entry/enum-entry or
;; brace-entry-open
(t (if (or (eq char-after-ip ?{)
(and c-special-brace-lists
(save-excursion
(goto-char indent-point)
(c-forward-syntactic-ws (c-point 'eol))
(c-looking-at-special-brace-list))))
(c-add-syntax 'brace-entry-open (point))
(t (cond
((or (eq char-after-ip ?{)
(and c-special-brace-lists
(save-excursion
(goto-char indent-point)
(c-forward-syntactic-ws (c-point 'eol))
(c-looking-at-special-brace-list))))
(c-add-syntax 'brace-entry-open (point)))
((eq (c-point 'eol) (1- indent-point))
(c-add-stmt-syntax (if enum-pos 'enum-entry 'brace-list-entry)
nil t containing-sexp
paren-state (point))))))))
paren-state (point)))
(t (c-add-syntax (if enum-pos 'enum-entry 'brace-list-entry)
(point)))))))))
;; CASE 10: A continued statement or top level construct.
((and (not (memq char-before-ip '(?\; ?:)))

View file

@ -1008,6 +1008,15 @@ Note that the style variables are always made local to the buffer."
'(put-text-property remove-text-properties
remove-list-of-text-properties)))
(defun c-locate-first-punctuation-prop (beg)
;; Scan the region (BEG (point)) for `syntax-table' punctuation text properties,
;; returning the position of the first found, or nil. Point is unchanged.
(let ((end (point)))
(goto-char beg)
(prog1 (if (c-search-forward-char-property 'syntax-table '(1) end)
(match-beginning 0))
(goto-char end))))
(defun c-depropertize-CPP (beg end)
;; Remove the punctuation syntax-table text property from the CPP parts of
;; (c-new-BEG c-new-END), and remove all syntax-table properties from any
@ -1032,7 +1041,10 @@ Note that the style variables are always made local to the buffer."
(search-forward-regexp c-anchored-cpp-prefix end 'bound)))
(goto-char (match-beginning 1))
(setq m-beg (point))
(c-end-of-macro))
(c-end-of-macro)
(c-truncate-lit-pos/state-cache
(or (c-locate-first-punctuation-prop m-beg) (point-max))))
(when (and ss-found (> (point) end))
(when c-ml-string-opener-re
(save-excursion (c-depropertize-ml-strings-in-region m-beg (point))))
@ -1044,6 +1056,8 @@ Note that the style variables are always made local to the buffer."
(goto-char (match-beginning 1))
(setq m-beg (point))
(c-end-of-macro)
(c-truncate-lit-pos/state-cache
(or (c-locate-first-punctuation-prop m-beg) (point-max)))
(when c-ml-string-opener-re
(save-excursion (c-depropertize-ml-strings-in-region m-beg (point))))
(c-clear-syntax-table-with-value-trim-caches m-beg (point) '(1)))))

View file

@ -1291,7 +1291,7 @@ can always override the use of `c-default-style' by making calls to
;; Anchor pos: Bol at the last line of previous construct.
(topmost-intro-cont . c-lineup-topmost-intro-cont)
;;Anchor pos: Bol at the topmost annotation line
(constraint-cont . +)
(constraint-cont . (c-lineup-item-after-paren-at-boi +))
;; Anchor pos: Boi of the starting requires/concept line
(annotation-top-cont . 0)
;;Anchor pos: Bol at the topmost annotation line
@ -1322,8 +1322,9 @@ can always override the use of `c-default-style' by making calls to
;; "typedef" token is ignored.
(brace-list-close . 0)
;; Anchor pos: At the brace list decl start(*).
(brace-list-intro . +)
(brace-list-intro . (c-lineup-item-after-paren-at-boi +))
;; Anchor pos: At the brace list decl start(*).
;; 2nd pos: At the open brace.
(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
@ -1335,9 +1336,10 @@ can always override the use of `c-default-style' by making calls to
;; enum construct.
(enum-close . 0)
;; Anchor pos: At the enum block open.
(enum-intro . +)
(enum-intro . (c-lineup-item-after-paren-at-boi +))
;; Anchor pos: The opening brace position when at boi, or boi
;; at the enum decl start(*).
;; 2nd pos: At the open brace.
(enum-entry . 0)
;; Anchor pos: Normally, boi of the line containing the
;; previous token, but if that line also contains the opening