emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

emacs-29 a3003492ace 4/6: Move c-ts-mode--statement-offset to c-ts-commo


From: Yuan Fu
Subject: emacs-29 a3003492ace 4/6: Move c-ts-mode--statement-offset to c-ts-common.el
Date: Sun, 29 Jan 2023 03:13:07 -0500 (EST)

branch: emacs-29
commit a3003492ace0571e5179500b42bbe44cb9763dbb
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>

    Move c-ts-mode--statement-offset to c-ts-common.el
    
    Now it can be used by other C-like languages.
    
    * lisp/progmodes/c-ts-common.el (c-ts-common-indent-offset):
    (c-ts-common-indent-block-type-regexp):
    (c-ts-common-indent-bracketless-type-regexp): New variables.
    (c-ts-common-statement-offset):
    (c-ts-mode--fix-bracketless-indent):
    (c-ts-mode--close-bracket-offset): New functions.
    
    * lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): Change
    c-ts-mode--statement-offset to c-ts-common-statement-offset.
    The (parent-is "if_statement") rules are now handled by (node-is
    "compound_statement").
    
    (c-ts-mode--statement-offset-post-processr):
    (c-ts-mode--statement-offset):
    (c-ts-mode--fix-bracketless-indent): Move to c-ts-common.el.
    
    (c-ts-base-mode): Setup c-ts-common stuff.
    
    * test/lisp/progmodes/c-ts-mode-resources/indent.erts: Make the test
    more challenging.
---
 lisp/progmodes/c-ts-common.el                      | 118 ++++++++++++++++++-
 lisp/progmodes/c-ts-mode.el                        | 125 +++------------------
 .../lisp/progmodes/c-ts-mode-resources/indent.erts |   8 +-
 3 files changed, 140 insertions(+), 111 deletions(-)

diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el
index 6671d4be5b6..2d4a0d41c2a 100644
--- a/lisp/progmodes/c-ts-common.el
+++ b/lisp/progmodes/c-ts-common.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2023 Free Software Foundation, Inc.
 
-;; Author     : 付禹安 (Yuan Fu) <casouri@gmail.com>
+;; Maintainer : 付禹安 (Yuan Fu) <casouri@gmail.com>
 ;; Keywords   : c c++ java javascript rust languages tree-sitter
 
 ;; This file is part of GNU Emacs.
@@ -22,7 +22,10 @@
 
 ;;; Commentary:
 ;;
-;; For C-like language major modes:
+;; This file contains functions that can be shared by C-like language
+;; major modes, like indenting and filling "/* */" block comments.
+;;
+;; For indenting and filling comments:
 ;;
 ;; - Use `c-ts-common-comment-setup' to setup comment variables and
 ;;   filling.
@@ -30,6 +33,14 @@
 ;; - Use simple-indent matcher `c-ts-common-looking-at-star' and
 ;;   anchor `c-ts-common-comment-start-after-first-star' for indenting
 ;;   block comments.  See `c-ts-mode--indent-styles' for example.
+;;
+;; For indenting statements:
+;;
+;; - Set `c-ts-common-indent-offset',
+;;   `c-ts-common-indent-block-type-regexp', and
+;;   `c-ts-common-indent-bracketless-type-regexp', then use simple-indent
+;;   offset `c-ts-common-statement-offset' in
+;;   `treesit-simple-indent-rules'.
 
 ;;; Code:
 
@@ -40,6 +51,8 @@
 (declare-function treesit-node-end "treesit.c")
 (declare-function treesit-node-type "treesit.c")
 
+;;; Comment indentation and filling
+
 (defun c-ts-common-looking-at-star (_n _p bol &rest _)
   "A tree-sitter simple indent matcher.
 Matches if there is a \"*\" after BOL."
@@ -242,6 +255,107 @@ Set up:
   (setq-local paragraph-separate paragraph-start)
   (setq-local fill-paragraph-function #'c-ts-common--fill-paragraph))
 
+;;; Statement indent
+
+(defvar c-ts-common-indent-offset nil
+  "Indent offset used by `c-ts-common' indent functions.
+
+This should be the symbol of the indent offset variable for the
+particular major mode.  This cannot be nil for `c-ts-common'
+statement indent functions to work.")
+
+(defvar c-ts-common-indent-block-type-regexp nil
+  "Regexp matching types of block nodes (i.e., {} blocks).
+
+This cannot be nil for `c-ts-common' statement indent functions
+to work.")
+
+(defvar c-ts-common-indent-bracketless-type-regexp nil
+  "A regexp matching types of bracketless constructs.
+
+These constructs include if, while, do-while, for statements.  In
+these statements, the body can omit the bracket, which requires
+special handling from our bracket-counting indent algorithm.
+
+This can be nil, meaning such special handling is not needed.")
+
+(defun c-ts-common-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 (i.e.,
+brackets) (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-common-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))
+    ;; If NODE is a opening bracket on its own line, take off one
+    ;; level because the code below assumes NODE is a statement
+    ;; _inside_ a {} block.
+    (when (string-match-p c-ts-common-indent-block-type-regexp
+                          (treesit-node-type node))
+      (cl-decf level))
+    ;; Go up the tree and compute indent level.
+    (while (if (eq node t)
+               (setq node parent)
+             node)
+      (when (string-match-p c-ts-common-indent-block-type-regexp
+                            (treesit-node-type node))
+        (cl-incf level)
+        (save-excursion
+          (goto-char (treesit-node-start node))
+          ;; Add an extra level if the opening bracket is on its own
+          ;; line, except (1) it's at top-level, or (2) it's immediate
+          ;; parent is another block.
+          (cond ((bolp) nil) ; Case (1).
+                ((let ((parent-type (treesit-node-type
+                                     (treesit-node-parent node))))
+                   ;; Case (2).
+                   (and parent-type
+                        (or (string-match-p
+                             c-ts-common-indent-block-type-regexp
+                             parent-type))))
+                 nil)
+                ;; Add a level.
+                ((looking-back (rx bol (* whitespace))
+                               (line-beginning-position))
+                 (cl-incf level)))))
+      (setq level (c-ts-mode--fix-bracketless-indent level node))
+      ;; Go up the tree.
+      (setq node (treesit-node-parent node)))
+    (* level (symbol-value c-ts-common-indent-offset))))
+
+(defun c-ts-mode--fix-bracketless-indent (level node)
+  "Takes LEVEL and NODE and return adjusted LEVEL.
+This fixes indentation for cases shown in bug#61026.  Basically
+in C-like syntax, statements like if, for, while sometimes omit
+the bracket in the body."
+  (let ((block-re c-ts-common-indent-block-type-regexp)
+        (statement-re
+         c-ts-common-indent-bracketless-type-regexp)
+        (node-type (treesit-node-type node))
+        (parent-type (treesit-node-type (treesit-node-parent node))))
+    (if (and block-re statement-re node-type parent-type
+             (not (string-match-p block-re node-type))
+             (string-match-p statement-re parent-type))
+        (1+ level)
+      level)))
+
+(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-common-statement-offset node parent)
+     (symbol-value c-ts-common-indent-offset)))
+
 (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 353c4c45479..b2f92b93193 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -63,11 +63,6 @@
 ;; will set up Emacs to use the C/C++ modes defined here for other
 ;; files, provided that you have the corresponding parser grammar
 ;; libraries installed.
-;;
-;; - Use variable `c-ts-mode-indent-block-type-regexp' with indent
-;;   offset c-ts-mode--statement-offset for indenting statements.
-;;   Again, see `c-ts-mode--indent-styles' for example.
-;;
 
 ;;; Code:
 
@@ -228,7 +223,7 @@ MODE is either `c' or `cpp'."
            ;; Labels.
            ((node-is "labeled_statement") parent-bol 0)
            ((parent-is "labeled_statement")
-            point-min c-ts-mode--statement-offset)
+            point-min c-ts-common-statement-offset)
 
            ((match "preproc_ifdef" "compound_statement") point-min 0)
            ((match "#endif" "preproc_ifdef") point-min 0)
@@ -237,15 +232,6 @@ MODE is either `c' or `cpp'."
            ((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")
-            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)
@@ -266,13 +252,16 @@ MODE is either `c' or `cpp'."
                  ;; Indent the body of namespace definitions.
                  ((parent-is "declaration_list") parent-bol 
c-ts-mode-indent-offset)))
 
+           ;; int[5] a = { 0, 0, 0, 0 };
            ((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)
-           ((parent-is "while_statement") parent-bol c-ts-mode-indent-offset)
-           ((parent-is "switch_statement") parent-bol c-ts-mode-indent-offset)
-           ((parent-is "case_statement") parent-bol c-ts-mode-indent-offset)
-           ((parent-is "do_statement") parent-bol c-ts-mode-indent-offset)
+           ((parent-is "enumerator_list") point-min 
c-ts-common-statement-offset)
+           ((parent-is "field_declaration_list") point-min 
c-ts-common-statement-offset)
+
+           ;; {} blocks.
+           ((node-is "}") point-min c-ts-mode--close-bracket-offset)
+           ((parent-is "compound_statement") point-min 
c-ts-common-statement-offset)
+           ((node-is "compound_statement") point-min 
c-ts-common-statement-offset)
+
            ,@(when (eq mode 'cpp)
                `(((node-is "field_initializer_list") parent-bol ,(* 
c-ts-mode-indent-offset 2)))))))
     `((gnu
@@ -311,90 +300,6 @@ NODE should be a labeled_statement."
                 "labeled_statement")
          (not (treesit-node-top-level func "compound_statement")))))
 
-(defvar c-ts-mode-indent-block-type-regexp
-  (rx (or "compound_statement"
-          "field_declaration_list"
-          "enumerator_list"))
-  "Regexp matching types of block nodes (i.e., {} blocks).")
-
-(defvar c-ts-mode--statement-offset-post-processr nil
-  "A functions that makes adjustments to `c-ts-mode--statement-offset'.
-
-This is a function that takes two arguments, the current indent
-level and the current node, and returns a new level.
-
-When `c-ts-mode--statement-offset' runs and go up the parse tree,
-it increments the indent level when some condition are met in
-each level.  At each level, after (possibly) incrementing the
-offset, it calls this function, passing it the current indent
-level and the current node, and use the return value as the new
-indent level.")
-
-(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))
-          ;; Add an extra level if the opening bracket is on its own
-          ;; line, except (1) it's at top-level, or (2) it's immediate
-          ;; parent is another block.
-          (cond ((bolp) nil) ; Case (1).
-                ((let ((parent-type (treesit-node-type
-                                     (treesit-node-parent node))))
-                   ;; Case (2).
-                   (and parent-type
-                        (string-match-p c-ts-mode-indent-block-type-regexp
-                                        parent-type)))
-                 nil)
-                ;; Add a level.
-                ((looking-back (rx bol (* whitespace))
-                               (line-beginning-position))
-                 (cl-incf level)))))
-      (when c-ts-mode--statement-offset-post-processr
-        (setq level (funcall c-ts-mode--statement-offset-post-processr
-                             level node))))
-    (* level c-ts-mode-indent-offset)))
-
-(defun c-ts-mode--fix-bracketless-indent (level node)
-  "Takes LEVEL and NODE and returns adjusted LEVEL.
-This fixes indentation for cases shown in bug#61026.  Basically
-in C/C++, constructs like if, for, while sometimes don't have
-bracket."
-  (if (and (not (equal (treesit-node-type node) "compound_statement"))
-           (member (treesit-node-type (treesit-node-parent node))
-                   '("if_statement" "while_statement" "do_statement"
-                     "for_statement")))
-      (1+ level)
-    level))
-
-(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))
-
 ;;; Font-lock
 
 (defvar c-ts-mode--preproc-keywords
@@ -824,8 +729,14 @@ the semicolon.  This function skips the semicolon."
   ;; Indent.
   (when (eq c-ts-mode-indent-style 'linux)
     (setq-local indent-tabs-mode t))
-  (setq-local c-ts-mode--statement-offset-post-processr
-              #'c-ts-mode--fix-bracketless-indent)
+  (setq-local c-ts-common-indent-offset 'c-ts-mode-indent-offset)
+  (setq-local c-ts-common-indent-block-type-regexp
+              (rx (or "compound_statement"
+                      "field_declaration_list"
+                      "enumerator_list")))
+  (setq-local c-ts-common-indent-bracketless-type-regexp
+              (rx (or "if_statement" "do_statement"
+                      "for_statement" "while_statement")))
 
   ;; Comment
   (c-ts-common-comment-setup)
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index 67654404a77..0ecbf922b15 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -114,7 +114,9 @@ int main() {
       {
         puts ("Hello");
       }
-  for (int i=0; i<5; i++)
+  for (int i=0;
+       i<5;
+       i++)
     if (true)
       {
         puts ("Hello");
@@ -141,7 +143,9 @@ int main() {
     if (true) {
       puts ("Hello");
     }
-  for (int i=0; i<5; i++)
+  for (int i=0;
+       i<5;
+       i++)
     if (true) {
       puts ("Hello");
     }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]