Subject: bug#74507: [PATCH] Indent compounds c-ts-mode when { is not BOL

From: Jørgen Kvalsvik <[email-masked]>
Date: Sun, 1 Dec 2024 10:51:38 +0100

On 12/1/24 10:25, Yuan Fu wrote:
> 
> 
>> On Nov 30, 2024, at 12:49 PM, Jørgen Kvalsvik <[email-masked]> wrote:
>>
>> On 11/30/24 01:16, Yuan Fu wrote:
>>>> On Nov 29, 2024, at 1:05 AM, Jørgen Kvalsvik <[email-masked]> wrote:
>>>>
>>>> On 11/29/24 08:57, Eli Zaretskii wrote:
>>>>>> Cc: [email-masked],[email-masked]
>>>>>> From: Jørgen Kvalsvik <[email-masked]>
>>>>>> Date: Sun, 24 Nov 2024 10:15:12 +0100
>>>>>>
>>>>>> * lisp/progmodes/c-ts-mode.el (c-ts-mode--parent-is-not-top-compound):
>>>>>> New function.
>>>>>> (c-ts-mode--indent-styles): Use it.
>>>>>> * test/lisp/progmodes/c-ts-mode-resources/indent.erts: New compound
>>>>>> statement test.
>>>>> Please make sure the lines here are not too long (see CONTRIBUTE for
>>>>> details).
>>>>>> +(defun c-ts-mode--parent-is-not-top-compound (_n parent &rest _)
>>>>>> +  "Matches when PARENT is not the top level compound statement,
>>>>>> +the {} that immediately follows the signature."
>>>>> The first line of a doc string should be a single complete sentence.
>>>>> Thanks.
>>>>
>>>> Ok. Yuan, would you like me to submit a revision?
>>> Since your assignment is already done, let’s just apply your patch, and I’ll rebase my changes on top of yours. So yeah, do send the revision patch, thanks!
>>> Yuan
>>
>> Certainly - I posted it on the bug tracker.
> 
> Thanks Jørgen. What did you use to generate the patch? For some reason I can’t apply it. My git skill isn’t that great so it could be my problem. If you can apply it fine maybe you can share the command you used?

I used git format-patch HEAD~1, and I just tested applying it to master 
with `git am 0001-Indent-compounds-in-c-ts-mode-when-is-not-BOL.patch' 
which worked.

> 
> BTW, the commit title is missing. When you add the title, you can also add the bug number. For example:
> 
> Improve c-ts-mode indentation for macros (bug#74507)
> 
> Yuan

Sure. I've attached a new patch with the bug in it. I tested it and it 
applies cleanly with `git am 
0001-Improve-c-ts-mode-compound-indents-bug-74507.patch'
From a6af85298de99cdbfc78c95659224c9dd7e6a4c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B8rgen=20Kvalsvik?= <[email-masked]>
Date: Tue, 19 Nov 2024 08:01:01 +0100
Subject: [PATCH] Improve c-ts-mode compound indents (bug#74507)

Properly indent the body of compound expressions, even when then
compound expression is not at the beginning of line and the parent is
not an if/for/while/etc., and matches the behavior of c-mode.

This fixes a problem that is common with macros and in testing
frameworks. For example, you expect this to indent:

TEST_CASE(1) {
    assert (...);
}

If the compound statement is the function body itself, don't apply this
new rule and instead guide by the parent and first sibling.

I'm sure there are subtle interactions that aren't handled properly by
checking for "function_definition" rather than something more general,
but it does fix the test case and the check can be improved as more
cases are found.

* lisp/progmodes/c-ts-mode.el:
(c-ts-mode--parent-is-not-top-compound): New function.
(c-ts-mode--indent-styles): Use it.
* test/lisp/progmodes/c-ts-mode-resources/indent.erts: New
compound statement test.
---
 lisp/progmodes/c-ts-mode.el                   |  9 ++++++
 .../progmodes/c-ts-mode-resources/indent.erts | 30 +++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index cbb103cfaf7..59b34ef6b8b 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -403,6 +403,12 @@ c-ts-mode--first-sibling
               (treesit-node-start parent)
               (line-end-position))))))
 
+(defun c-ts-mode--parent-is-not-top-compound (_n parent &rest _)
+  "Matches when PARENT is not the top level compound statement.
+The top-level compound is the {} that immediately follows the function
+signature."
+  (not (equal "function_definition" (treesit-node-type (treesit-node-parent parent)))))
+
 (defun c-ts-mode--indent-styles (mode)
   "Indent rules supported by `c-ts-mode'.
 MODE is either `c' or `cpp'."
@@ -479,6 +485,7 @@ c-ts-mode--indent-styles
            ;; Closing bracket.  This should be before initializer_list
            ;; (and probably others) rule because that rule (and other
            ;; similar rules) will match the closing bracket.  (Bug#61398)
+           ((and (node-is "}") c-ts-mode--parent-is-not-top-compound) parent-bol 0)
            ((node-is "}") standalone-parent 0)
            ,@(when (eq mode 'cpp)
                '(((node-is "access_specifier") parent-bol 0)
@@ -498,6 +505,8 @@ c-ts-mode--indent-styles
            ((parent-is "field_declaration_list") c-ts-mode--anchor-prev-sibling 0)
 
            ;; Statement in {} blocks.
+           ((and (parent-is "compound_statement") c-ts-mode--parent-is-not-top-compound)
+            parent-bol c-ts-mode-indent-offset)
            ((or (and (parent-is "compound_statement")
                      ;; If the previous sibling(s) are not on their
                      ;; own line, indent as if this node is the first
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index 2f3540c3970..61e61677ed7 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -223,6 +223,36 @@ make_pair(int long_identifier_a[], int long_identifier_b[],
 
 =-=-=
 
+Name: Compound Statement after code
+
+=-=
+#define IOTA(var, n) for (int var = 0; var != (n); ++var)
+int main()
+{
+IOTA (v, 10) {
+printf("%d ", v);
+}
+
+const char *msg = "Hello, world!"; {
+puts("Hello, world!");
+}
+}
+
+=-=
+#define IOTA(var, n) for (int var = 0; var != (n); ++var)
+int main()
+{
+  IOTA (v, 10) {
+    printf("%d ", v);
+  }
+
+  const char *msg = "Hello, world!"; {
+    puts("Hello, world!");
+  }
+}
+
+=-=-=
+
 Name: Switch-Case statement
 
 =-=
-- 
2.39.5