From: Yuan Fu Date: Sun, 15 Jan 2023 08:16:58 +0000 (-0800) Subject: Fix statement indent for c-ts-mode (bug#59686) (bug#60280) X-Git-Tag: emacs-29.0.90~720^2~3 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=189d976dbae;p=emacs.git Fix statement indent for c-ts-mode (bug#59686) (bug#60280) Instead of trying to figure out the correct anchor, now we just count the layers of {} blocks between the node and the root node. * lisp/progmodes/c-ts-mode.el: (c-ts-mode--indent-styles): Use new offset functions c-ts-mode--close-bracket-offset and c-ts-mode--statement-offset. (c-ts-mode--bracket-children-anchor): Remove function. (c-ts-mode--top-level-label-matcher): New variable. (c-ts-mode--statement-offset) (c-ts-mode--close-bracket-offset): New offset functions. --- diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 2e2bd6beeb6..cc1f183fd73 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -118,7 +118,6 @@ MODE is either `c' or `cpp'." `(((parent-is "translation_unit") parent-bol 0) ((node-is ")") parent 1) ((node-is "]") parent-bol 0) - ((node-is "}") c-ts-mode--bracket-children-anchor 0) ((node-is "else") parent-bol 0) ((node-is "case") parent-bol 0) ((node-is "preproc_arg") no-indent) @@ -138,8 +137,16 @@ MODE is either `c' or `cpp'." ((match "#endif" "preproc_if") point-min 0) ((match "preproc_function_def" "compound_statement") point-min 0) ((match "preproc_call" "compound_statement") point-min 0) + + ;; {} blocks. + ((node-is "}") point-min c-ts-mode--close-bracket-offset) ((parent-is "compound_statement") - c-ts-mode--bracket-children-anchor c-ts-mode-indent-offset) + point-min c-ts-mode--statement-offset) + ((parent-is "enumerator_list") + point-min c-ts-mode--statement-offset) + ((parent-is "field_declaration_list") + point-min c-ts-mode--statement-offset) + ((parent-is "function_definition") parent-bol 0) ((parent-is "conditional_expression") first-sibling 0) ((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset) @@ -155,12 +162,11 @@ MODE is either `c' or `cpp'." ((query "(for_statement update: (_) @indent)") parent-bol 5) ((query "(call_expression arguments: (_) @indent)") parent c-ts-mode-indent-offset) ((parent-is "call_expression") parent 0) - ((parent-is "enumerator_list") parent-bol c-ts-mode-indent-offset) ,@(when (eq mode 'cpp) '(((node-is "access_specifier") parent-bol 0) ;; Indent the body of namespace definitions. ((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset))) - ((parent-is "field_declaration_list") parent-bol c-ts-mode-indent-offset) + ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset) ((parent-is "if_statement") parent-bol c-ts-mode-indent-offset) ((parent-is "for_statement") parent-bol c-ts-mode-indent-offset) @@ -215,20 +221,50 @@ NODE should be a labeled_statement." "labeled_statement") (not (treesit-node-top-level func "function_definition"))))) -(defun c-ts-mode--bracket-children-anchor (_n parent &rest _) - "This anchor is used for children of a compound_statement. -So anything inside a {} block. PARENT should be the -compound_statement. This anchor looks at the {, if itson its own -line, anchor at it, if it has stuff before it, anchor at the -beginning of grandparent." - (save-excursion - (goto-char (treesit-node-start parent)) - (let ((bol (line-beginning-position))) - (skip-chars-backward " \t") - (treesit-node-start - (if (< bol (point)) - (treesit-node-parent parent) - parent))))) +(defvar c-ts-mode-indent-block-type-regexp + (rx (or "compound_statement" + "field_declaration_list" + "enumeratior_list")) + "Regexp matching types of block nodes (i.e., {} blocks).") + +(defun c-ts-mode--statement-offset (node parent &rest _) + "This anchor is used for children of a statement inside a block. + +This function basically counts the number of block nodes (defined +by `c-ts-mode--indent-block-type-regexp') between NODE and the +root node (not counting NODE itself), and multiply that by +`c-ts-mode-indent-offset'. + +To support GNU style, on each block level, this function also +checks whether the opening bracket { is on its own line, if so, +it adds an extra level, except for the top-level. + +PARENT is NODE's parent." + (let ((level 0)) + ;; If point is on an empty line, NODE would be nil, but we pretend + ;; there is a statement node. + (when (null node) + (setq node t)) + (while (if (eq node t) + (setq node parent) + (setq node (treesit-node-parent node))) + (when (string-match-p c-ts-mode-indent-block-type-regexp + (treesit-node-type node)) + (cl-incf level) + (save-excursion + (goto-char (treesit-node-start node)) + (cond ((bolp) nil) + ((looking-back (rx bol (* whitespace)) + (line-beginning-position)) + (cl-incf level)))))) + (* level c-ts-mode-indent-offset))) + +(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. +PARENT is NODE's parent." + (- (c-ts-mode--statement-offset node parent) + c-ts-mode-indent-offset)) (defun c-ts-mode--looking-at-star (_n _p bol &rest _) "A tree-sitter simple indent matcher.