From 23d859a6bedab436b87db2458f15a69403bbef99 Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Sun, 5 Feb 2023 08:49:08 +0100 Subject: [PATCH] Use c-ts-common-statement-offset in java-ts-mode (bug#61142) * lisp/progmodes/java-ts-mode.el (java-ts-mode--indent-rules): Add new matchers to enable c-ts-common machinery. (java-ts-mode): Add regexps. * lisp/progmodes/c-ts-common.el (c-ts-common-statement-offset): Fix typo in documentation and use the new if statement helpers. (c-ts-common-if-statement-regexp): New defvar. (c-ts-common-nestable-if-statement-p): New defvar. (c-ts-common--fix-nestable-if-statement): New helper. * test/lisp/progmodes/c-ts-mode-resources/indent.erts: Add test for complicated bracket matching indentation. * lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): Add indent rules for bracketless statements. --- lisp/progmodes/c-ts-common.el | 34 +++++++++++++- lisp/progmodes/c-ts-mode.el | 7 +++ lisp/progmodes/java-ts-mode.el | 36 +++++++++++---- .../progmodes/c-ts-mode-resources/indent.erts | 45 +++++++++++++++++++ 4 files changed, 112 insertions(+), 10 deletions(-) diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el index 8729cae4ba..6767f10a9e 100644 --- a/lisp/progmodes/c-ts-common.el +++ b/lisp/progmodes/c-ts-common.el @@ -281,11 +281,22 @@ c-ts-common-indent-bracketless-type-regexp This can be nil, meaning such special handling is not needed.") +(defvar c-ts-common-if-statement-regexp "if_statement" + "Regexp used to select an if statement in a C like language. + +This can be set to a different regexp if needed.") + +(defvar c-ts-common-nestable-if-statement-p t + "Does the current parser nest if-else statements? + +t if the current tree-sitter grammar nests the else if +statements, nil otherwise.") + (defun c-ts-common-statement-offset (node parent bol &rest _) "This anchor is used for children of a statement inside a block. This function basically counts the number of block nodes (i.e., -brackets) (defined by `c-ts-mode--indent-block-type-regexp') +brackets) (defined by `c-ts-common-indent-block-type-regexp') between NODE and the root node (not counting NODE itself), and multiply that by `c-ts-common-indent-offset'. @@ -312,6 +323,9 @@ c-ts-common-statement-offset (while (if (eq node t) (setq node parent) node) + ;; Subtract one indent level if the language nests + ;; if-statements and node is if_statement. + (setq level (c-ts-common--fix-nestable-if-statement level node)) (when (string-match-p c-ts-common-indent-block-type-regexp (treesit-node-type node)) (cl-incf level) @@ -354,6 +368,24 @@ c-ts-mode--fix-bracketless-indent (1+ level) level))) +(defun c-ts-common--fix-nestable-if-statement (level node) + "Takes LEVEL and NODE and return adjusted LEVEL. +Look at the type of NODE, when it is an if-statement node, as +defined by `c-ts-common-if-statement-regexp' and its parent is +also an if-statement node, subtract one level. Otherwise return +the value unchanged. Whether or not if-statements are nestable +is controlled by `c-ts-common-nestable-if-statement-p'." + ;; This fixes indentation for cases shown in bug#61142. + (or (and node + (equal (treesit-node-type (treesit-node-prev-sibling node)) "else") + (treesit-node-parent node) + c-ts-common-nestable-if-statement-p + (equal (treesit-node-type node) c-ts-common-if-statement-regexp) + (equal (treesit-node-type (treesit-node-parent node)) + c-ts-common-if-statement-regexp) + (cl-decf level)) + level)) + (provide 'c-ts-common) ;;; c-ts-common.el ends here diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 5093c3980b..e3d8c9ddad 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -238,6 +238,13 @@ c-ts-mode--indent-styles ((parent-is "labeled_statement") point-min c-ts-common-statement-offset) + ;; Bracketless statement matchers. + ((match nil "while_statement" "condition") parent-bol c-ts-mode-indent-offset) + ((match nil "if_statement" "consequence") parent-bol c-ts-mode-indent-offset) + ((match nil "if_statement" "alternative") parent-bol c-ts-mode-indent-offset) + ((match nil "do_statement" "body") parent-bol c-ts-mode-indent-offset) + ((match nil "for_statement" "body") parent-bol c-ts-mode-indent-offset) + ((match "preproc_ifdef" "compound_statement") point-min 0) ((match "#endif" "preproc_ifdef") point-min 0) ((match "preproc_if" "compound_statement") point-min 0) diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index b9f7894095..1d7bdb0722 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -70,22 +70,25 @@ java-ts-mode--syntax-table (defvar java-ts-mode--indent-rules `((java ((parent-is "program") point-min 0) - ((node-is "}") (and parent parent-bol) 0) + ((match "}" "element_value_array_initializer") + parent-bol 0) + ((node-is "}") point-min c-ts-common-statement-offset) ((node-is ")") parent-bol 0) + ((node-is "else") parent-bol 0) ((node-is "]") parent-bol 0) ((and (parent-is "comment") c-ts-common-looking-at-star) c-ts-common-comment-start-after-first-star -1) ((parent-is "comment") prev-adaptive-prefix 0) ((parent-is "text_block") no-indent) - ((parent-is "class_body") parent-bol java-ts-mode-indent-offset) + ((parent-is "class_body") point-min c-ts-common-statement-offset) ((parent-is "array_initializer") parent-bol java-ts-mode-indent-offset) - ((parent-is "annotation_type_body") parent-bol java-ts-mode-indent-offset) - ((parent-is "interface_body") parent-bol java-ts-mode-indent-offset) - ((parent-is "constructor_body") parent-bol java-ts-mode-indent-offset) + ((parent-is "annotation_type_body") point-min c-ts-common-statement-offset) + ((parent-is "interface_body") point-min c-ts-common-statement-offset) + ((parent-is "constructor_body") point-min c-ts-common-statement-offset) ((parent-is "enum_body_declarations") parent-bol 0) - ((parent-is "enum_body") parent-bol java-ts-mode-indent-offset) - ((parent-is "switch_block") parent-bol java-ts-mode-indent-offset) - ((parent-is "record_declaration_body") parent-bol java-ts-mode-indent-offset) + ((parent-is "enum_body") point-min c-ts-common-statement-offset) + ((parent-is "switch_block") point-min c-ts-common-statement-offset) + ((parent-is "record_declaration_body") point-min c-ts-common-statement-offset) ((query "(method_declaration (block _ @indent))") parent-bol java-ts-mode-indent-offset) ((query "(method_declaration (block (_) @indent))") parent-bol java-ts-mode-indent-offset) ((parent-is "local_variable_declaration") parent-bol java-ts-mode-indent-offset) @@ -118,7 +121,7 @@ java-ts-mode--indent-rules ((parent-is "case_statement") parent-bol java-ts-mode-indent-offset) ((parent-is "labeled_statement") parent-bol java-ts-mode-indent-offset) ((parent-is "do_statement") parent-bol java-ts-mode-indent-offset) - ((parent-is "block") (and parent parent-bol) java-ts-mode-indent-offset))) + ((parent-is "block") point-min c-ts-common-statement-offset))) "Tree-sitter indent rules.") (defvar java-ts-mode--keywords @@ -300,6 +303,21 @@ java-ts-mode (c-ts-common-comment-setup) ;; Indent. + (setq-local c-ts-common-indent-block-type-regexp + (regexp-opt '("class_body" + "array_initializer" + "constructor_body" + "annotation_type_body" + "interface_body" + "enum_body" + "switch_block" + "record_declaration_body" + "block"))) + (setq-local c-ts-common-indent-bracketless-type-regexp + (regexp-opt '("if_statement" + "for_statement" + "while_statement"))) + (setq-local c-ts-common-indent-offset 'java-ts-mode-indent-offset) (setq-local treesit-simple-indent-rules java-ts-mode--indent-rules) ;; Electric diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts index 7dcc3b0fb3..6f64e1e795 100644 --- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts @@ -244,3 +244,48 @@ int main() { } } =-=-= + +Name: Complicated mixed bracket matching indentation (bug#61142) + +=-= +void foo( + int foo) { + for (;;) + return 5; + + if (a == 0 + && b == 1 + && foo) + { + return 0; + } + else if (a == 1) + { + return 1; + } + else if (true) + return 5; + else + { + if (a == 0 + && b == 1 + && foo) + for ( + int i = 0; + i < 5; + i++) + if (true) + do + i = 5; + while (true); + else if (false) + { + return 6; + } + else + if (true + && false) + return 6; + } +} +=-=-= -- 2.34.1