]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix c-ts-mode indentation (bug#67357)
authornverno <noah.v.peart@gmail.com>
Wed, 22 Nov 2023 00:33:04 +0000 (16:33 -0800)
committerEshel Yaron <me@eshelyaron.com>
Mon, 11 Dec 2023 06:42:18 +0000 (07:42 +0100)
1. In a compund_statement, we indent the first sibling against the
parent, and the rest siblings against their previous sibling.  But
this strategy falls apart when the first sibling is not on its own
line.  We should regard the first sibling that is on its own line as
the "first sibling"", and indent it against the parent.

2. In linux style, in a do-while statement, if the do-body is
bracket-less, the "while" keyword is indented to the same level as the
do-body.  It should be indented to align with the "do" keyword
instead.

* lisp/progmodes/c-ts-mode.el:
(c-ts-mode--no-prev-standalone-sibling): New function.
(c-ts-mode--indent-styles): Use
c-ts-mode--no-prev-standalone-sibling. Add while keyword indent rule.
* test/lisp/progmodes/c-ts-mode-resources/indent.erts: New tests.

(cherry picked from commit 08fc6bace202a13d93fc76943c41f19acaab9c73)

lisp/progmodes/c-ts-mode.el
test/lisp/progmodes/c-ts-mode-resources/indent.erts

index 2279d00b7a1f13ee4c0823ba6d99f378fe31bc30..71e20c87f14dacdc6ca1302adba0c0995d0a9b17 100644 (file)
@@ -322,7 +322,8 @@ PARENT and BOL are like other anchor functions."
                                (treesit-node-parent prev-sibling) t)))
           ;; If the start of the previous sibling isn't at the
           ;; beginning of a line, something's probably not quite
-          ;; right, go a step further.
+          ;; right, go a step further. (E.g., comment after a
+          ;; statement.)
           (_ (goto-char (treesit-node-start prev-sibling))
              (if (looking-back (rx bol (* whitespace))
                                (line-beginning-position))
@@ -365,6 +366,19 @@ PARENT, BOL, ARGS are the same as other anchor functions."
       (back-to-indentation)
       (looking-at-p regexp))))
 
+(defun c-ts-mode--first-sibling (node parent &rest _)
+  "Matches when NODE is the \"first sibling\".
+\"First sibling\" is defined as: the first child node of PARENT
+such that it's on its own line.  NODE is the node to match and
+PARENT is its parent."
+  (let ((prev-sibling (treesit-node-prev-sibling node t)))
+    (or (null prev-sibling)
+        (save-excursion
+          (goto-char (treesit-node-start prev-sibling))
+          (<= (line-beginning-position)
+              (treesit-node-start parent)
+              (line-end-position))))))
+
 (defun c-ts-mode--indent-styles (mode)
   "Indent rules supported by `c-ts-mode'.
 MODE is either `c' or `cpp'."
@@ -458,7 +472,11 @@ MODE is either `c' or `cpp'."
            ((parent-is "field_declaration_list") c-ts-mode--anchor-prev-sibling 0)
 
            ;; Statement in {} blocks.
-           ((or (match nil "compound_statement" nil 1 1)
+           ((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
+                     ;; sibling (Bug#67357)
+                     c-ts-mode--first-sibling)
                 (match null "compound_statement"))
             standalone-parent c-ts-mode-indent-offset)
            ((parent-is "compound_statement") c-ts-mode--anchor-prev-sibling 0)
@@ -471,6 +489,7 @@ MODE is either `c' or `cpp'."
            ((parent-is "if_statement") standalone-parent c-ts-mode-indent-offset)
            ((parent-is "else_clause") standalone-parent c-ts-mode-indent-offset)
            ((parent-is "for_statement") standalone-parent c-ts-mode-indent-offset)
+           ((match "while" "do_statement") parent-bol 0) ; (do_statement "while")
            ((parent-is "while_statement") standalone-parent c-ts-mode-indent-offset)
            ((parent-is "do_statement") standalone-parent c-ts-mode-indent-offset)
 
index bac76fb7378b795a190c2b94b892bcdb75941bef..2fd26d75844d59fdec8fee0244af4b322fbc5771 100644 (file)
@@ -330,7 +330,7 @@ label:
 
 Name: Bracket-less Block-Statement (Linux Style) (bug#61026)
 
-=-=-=
+=-=
 int main() {
   while (true)
     if (true) {
@@ -351,6 +351,8 @@ int main() {
     if (true) {
       puts ("Hello");
     }
+    else
+      puts("Hello");
 }
 =-=-=
 
@@ -399,6 +401,34 @@ void foo(
 }
 =-=-=
 
+Name: Block-Statement where first siblings are comments (Linux Style)
+
+=-=
+int main() {
+  while (true) { /* foo */
+    if (true) { // bar
+      puts ("Hello");
+    }
+  }
+  for (;;) {  // 1. fooo
+    /* 2. baaa */
+    /* 3. rrr */
+    if (true)
+      // 2. baaa
+      puts ("Hello");
+  }
+  if (1) { // 1
+    /*
+     * 2
+     */
+    if (1) /*3*/ {
+      /* 4 */
+      puts("Hello");
+    }
+  }
+}
+=-=-=
+
 Name: Initializer List (Linux Style) (Bug#61398)
 
 =-=
@@ -498,3 +528,19 @@ main (void)
 {
   |
 =-=-=
+
+Code:
+  (lambda ()
+    (c-ts-mode)
+    (setq-local indent-tabs-mode nil)
+    (goto-line 3)
+    (indent-for-tab-command))
+
+Name: Block-Statement where previous sibling is comment
+
+=-=
+int main() {
+    puts ("Hello"); // unusual indent and has trailing comment.
+    return true; // Should align with previous non-comment sibling (rather than one level up against parent).
+}
+=-=-=