Subject: bug#61502: 29.0.60; c-ts-mode auto-indent not working

From: Theodor Thornhill <[email-masked]>
Date: Tue, 14 Feb 2023 20:41:04 +0100

Eli Zaretskii <[email-masked]> writes:

>> From: Pankaj Jangid <[email-masked]>
>> Date: Tue, 14 Feb 2023 10:06:13 +0530
>> 
>> 
>> The auto-indent is not working when using c-ts-mode.
>> 
>> Steps:
>> 
>> 1. create a new file test.c
>> 
>> 2. After typing following snippet, the indentation should work
>> automatically on RET. But even the TAB is not indenting the next line
>> (after the RET),
>> 
>> --8<---------------cut here---------------start------------->8---
>> int main()
>> {
>> --8<---------------cut here---------------end--------------->8---
>
> Keep typing whatever code you wan "int main" to include, and it will
> auto-indent soon enough.

Yeah, but.

>
> So I'm not sure your expectations are necessarily true; they could be
> just something you are used to in CC mode.  But I'll let Yuan and Theo
> chime in and tell whether a single RET here is supposed to
> auto-indent.  Does c-ts-mode really always reindents on RET?

I agree this is a little unexpected. Let's consider this code:

```
int
main
{
  for (;;)
    {|
}
```

If you press RET if point at | you'll see we indent immediately, even
though there is no closing bracket.  This is because of how
treesit-indent defaults to treesit-node-on when there is no node at
point.  So in the example without the for loop the parent is then set to
whatever treesit-node-on returns, which in this case is the root
node. That means that the rule for translation_unit is selected, which
is:

         `(((parent-is "translation_unit") point-min 0)

However, what's interesting here is that treesit-indent selects an
"unexisting" node as the "smallest-node".  Specifically that is:

         #<treesit-node "}" in 13-13>

This node in turn will return "compound_statement" if you look for its
parent.  It seems some parsers detects these nodes, so maybe we should
add some handling for that?  Some "block-closers" code in
treesit-node-on, so that treesit-node-on doesn't default to the root
node, but rather the compound_statement?

I'm not sure this explanation was easy to follow at all, but I'll add a
hack in a diff to make the point hopefully a little clearer.

What do you think?

Theo

diff --git a/lisp/treesit.el b/lisp/treesit.el
index 749781894b..300a703515 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1418,6 +1418,8 @@ treesit--indent-1
          ;; encompass the whitespace.
          (parent (cond ((and node parser)
                         (treesit-node-parent node))
+                       ((equal (treesit-node-type smallest-node) "}")
+                        (treesit-node-parent smallest-node))
                        (t (treesit-node-on bol bol)))))
       (funcall treesit-indent-function node parent bol))))