summaryrefslogtreecommitdiff
path: root/lisp/progmodes/c-ts-mode.el
diff options
context:
space:
mode:
authornverno <noah.v.peart@gmail.com>2023-11-21 16:33:04 -0800
committerYuan Fu <casouri@gmail.com>2023-12-10 01:05:22 -0800
commit08fc6bace202a13d93fc76943c41f19acaab9c73 (patch)
tree8cf452ecf590a8df8e08008ecefcdb1795b7a540 /lisp/progmodes/c-ts-mode.el
parent71bc2815ccdf443d49865ea913048658a6634823 (diff)
downloademacs-08fc6bace202a13d93fc76943c41f19acaab9c73.tar.gz
emacs-08fc6bace202a13d93fc76943c41f19acaab9c73.tar.bz2
emacs-08fc6bace202a13d93fc76943c41f19acaab9c73.zip
Fix c-ts-mode indentation (bug#67357)
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.
Diffstat (limited to 'lisp/progmodes/c-ts-mode.el')
-rw-r--r--lisp/progmodes/c-ts-mode.el23
1 files changed, 21 insertions, 2 deletions
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 21fb0ca9e53..677273afaac 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -321,7 +321,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))
@@ -364,6 +365,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'."
@@ -457,7 +471,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)
@@ -470,6 +488,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)