Fix indentation for c-ts-mode (bug#61026)

Fix indentation for things like

  while (true)
    if (true)
      {
        puts ("Hello");
      }

Note that the outer while loop omits brackets.

* lisp/progmodes/c-ts-mode.el:
(c-ts-mode--statement-offset-post-processr): New variable.
(c-ts-mode--statement-offset): Use the new function.
(c-ts-mode--fix-bracketless-indent): New function.
(c-ts-base-mode): Use the new function.
* test/lisp/progmodes/c-ts-mode-resources/indent.erts: New tests.
This commit is contained in:
Yuan Fu 2023-01-25 23:47:27 -08:00
parent 4bd06ce2a9
commit cdf74254ff
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
2 changed files with 83 additions and 1 deletions

View file

@ -279,6 +279,19 @@ NODE should be a labeled_statement."
"enumerator_list"))
"Regexp matching types of block nodes (i.e., {} blocks).")
(defvar c-ts-mode--statement-offset-post-processr nil
"A functions that makes adjustments to `c-ts-mode--statement-offset'.
This is a function that takes two arguments, the current indent
level and the current node, and returns a new level.
When `c-ts-mode--statement-offset' runs and go up the parse tree,
it increments the indent level when some condition are met in
each level. At each level, after (possibly) incrementing the
offset, it calls this function, passing it the current indent
level and the current node, and use the return value as the new
indent level.")
(defun c-ts-mode--statement-offset (node parent &rest _)
"This anchor is used for children of a statement inside a block.
@ -319,9 +332,24 @@ PARENT is NODE's parent."
;; Add a level.
((looking-back (rx bol (* whitespace))
(line-beginning-position))
(cl-incf level))))))
(cl-incf level)))))
(when c-ts-mode--statement-offset-post-processr
(setq level (funcall c-ts-mode--statement-offset-post-processr
level node))))
(* level c-ts-mode-indent-offset)))
(defun c-ts-mode--fix-bracketless-indent (level node)
"Takes LEVEL and NODE and returns adjusted LEVEL.
This fixes indentation for cases shown in bug#61026. Basically
in C/C++, constructs like if, for, while sometimes don't have
bracket."
(if (and (not (equal (treesit-node-type node) "compound_statement"))
(member (treesit-node-type (treesit-node-parent node))
'("if_statement" "while_statement" "do_statement"
"for_statement")))
(1+ level)
level))
(defun c-ts-mode--close-bracket-offset (node parent &rest _)
"Offset for the closing bracket, NODE.
It's basically one level less that the statements in the block.
@ -758,6 +786,8 @@ the semicolon. This function skips the semicolon."
;; Indent.
(when (eq c-ts-mode-indent-style 'linux)
(setq-local indent-tabs-mode t))
(setq-local c-ts-mode--statement-offset-post-processr
#'c-ts-mode--fix-bracketless-indent)
;; Comment
(c-ts-common-comment-setup)

View file

@ -105,6 +105,58 @@ main (int argc,
}
=-=-=
Name: Bracket-less Block-Statement (GNU Style) (bug#61026)
=-=
int main() {
while (true)
if (true)
{
puts ("Hello");
}
for (int i=0; i<5; i++)
if (true)
{
puts ("Hello");
}
do
if (true)
{
puts ("Hello");
}
while (true);
if (true)
if (true)
{
puts ("Hello");
}
}
=-=-=
Name: Bracket-less Block-Statement (Linux Style) (bug#61026)
=-=-=
int main() {
while (true)
if (true) {
puts ("Hello");
}
for (int i=0; i<5; i++)
if (true) {
puts ("Hello");
}
do
if (true) {
puts ("Hello");
}
while (true);
if (true)
if (true) {
puts ("Hello");
}
}
=-=-=
Name: Multiline Parameter List (bug#60398)
=-=