From 836044f329a0a96810f2d88471cb040b9d373cce Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 4 Mar 2023 14:39:44 -0800 Subject: [PATCH] Fix c-ts-mode preproc directive indentation Mentioned in bug#61893, although not the subject of that report. This change fixes indentation for nested directives. For example, when the directive involves elif and the like, the elif is nested in the if directive, so simply using grand-parent and great-grand-parent for anchor is insufficient, because the nesting can grow arbitrarily. The test added also covers the last preproc fix. * lisp/progmodes/c-ts-mode.el: (c-ts-mode--standalone-parent-skip-preproc): New function. (c-ts-mode--indent-styles): New rules. * test/lisp/progmodes/c-ts-mode-resources/indent-preproc.erts: New test. --- lisp/progmodes/c-ts-mode.el | 36 +++++++++++++++++-- .../c-ts-mode-resources/indent-preproc.erts | 34 ++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 05c471e6fb4..f40bbc57eb5 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -299,6 +299,23 @@ PARENT and BOL are like other anchor functions." ;; prev-sibling doesn't have a child. (treesit-node-start prev-sibling))) +(defun c-ts-mode--standalone-parent-skip-preproc (_n parent &rest _) + "Like the standalone-parent anchor but skips preproc nodes. +PARENT is the same as other anchor functions." + (save-excursion + (treesit-node-start + (treesit-parent-until + ;; Use PARENT rather than NODE, to handle the case where NODE is + ;; nil. + parent (lambda (node) + (and node + (not (string-match "preproc" (treesit-node-type node))) + (progn + (goto-char (treesit-node-start node)) + (looking-back (rx bol (* whitespace)) + (line-beginning-position))))) + t)))) + (defun c-ts-mode--standalone-grandparent (_node parent bol &rest args) "Like the standalone-parent anchor but pass it the grandparent. PARENT, BOL, ARGS are the same as other anchor functions." @@ -330,13 +347,28 @@ MODE is either `c' or `cpp'." ((parent-is "labeled_statement") c-ts-mode--standalone-grandparent c-ts-mode-indent-offset) + ;; Preproc directives ((node-is "preproc") column-0 0) ((node-is "#endif") column-0 0) ((match "preproc_call" "compound_statement") column-0 0) + ;; Top-level things under a preproc directive. Note that + ;; "preproc" matches more than one type: it matches + ;; preproc_if, preproc_elif, etc. ((n-p-gp nil "preproc" "translation_unit") column-0 0) - ((n-p-gp nil "\n" "preproc") great-grand-parent c-ts-mode--preproc-offset) - ((parent-is "preproc") grand-parent c-ts-mode-indent-offset) + ;; Indent rule for an empty line after a preproc directive. + ((and no-node (parent-is ,(rx (or "\n" "preproc")))) + c-ts-mode--standalone-parent-skip-preproc c-ts-mode--preproc-offset) + ;; Statement under a preproc directive, the first statement + ;; indents against parent, the rest statements indent to + ;; their prev-sibling. + ((match nil ,(rx "preproc_" (or "if" "elif")) nil 3 3) + c-ts-mode--standalone-parent-skip-preproc c-ts-mode-indent-offset) + ((match nil "preproc_ifdef" nil 2 2) + c-ts-mode--standalone-parent-skip-preproc c-ts-mode-indent-offset) + ((match nil "preproc_else" nil 1 1) + c-ts-mode--standalone-parent-skip-preproc c-ts-mode-indent-offset) + ((parent-is "preproc") c-ts-mode--anchor-prev-sibling 0) ((parent-is "function_definition") parent-bol 0) ((parent-is "conditional_expression") first-sibling 0) diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent-preproc.erts b/test/lisp/progmodes/c-ts-mode-resources/indent-preproc.erts index 57610b5483e..0f9256ad984 100644 --- a/test/lisp/progmodes/c-ts-mode-resources/indent-preproc.erts +++ b/test/lisp/progmodes/c-ts-mode-resources/indent-preproc.erts @@ -44,3 +44,37 @@ static void /* */ static void =-=-= + +Code: + (lambda () + (c-ts-mode) + (setq-local indent-tabs-mode nil) + (setq-local c-ts-mode-indent-offset 2) + (c-ts-mode-set-style 'gnu) + (indent-region (point-min) (point-max))) + +Name: Prev-Sibling When Prev-Sibling is Preproc + +=-= +static void +free_glyph_pool (struct glyph_pool *pool) +{ + if (pool) + { +#if defined GLYPH_DEBUG + int c = 1; +#endif + int check_this = 3; + +#ifdef stuff + int c = 1; +#elif defined stuff + int e = 5; +#else + int d = 11; + int f = 11; +#endif + int check_this = 3; + } +} +=-=-= -- 2.39.2