]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix tree-sitter comment indentation for C-like languages
authorYuan Fu <casouri@gmail.com>
Sun, 20 Nov 2022 01:59:14 +0000 (17:59 -0800)
committerYuan Fu <casouri@gmail.com>
Sun, 20 Nov 2022 02:36:08 +0000 (18:36 -0800)
The goal is to indent like this:

/* comment
   comment  --> This line aligns with the beginning of the first line
 */         --> This line aligns with the opening comment token

* lisp/treesit.el (treesit-comment-start)
(treesit-comment-end): New variables.
(treesit-simple-indent-presets): New preset comment-end,
comment-start, comment-start-skip

* lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles)
(c-ts-mode)
* lisp/progmodes/java-ts-mode.el (java-ts-mode--indent-rules)
(java-ts-mode)
* lisp/progmodes/js.el (js--treesit-indent-rules)
(js-ts-mode)
* lisp/progmodes/ts-mode.el (ts-mode--indent-rules)
(ts-mode): Add identical indent rules to each mode, and set identical
treesit-comment-start/end's.

* doc/lispref/modes.texi (Parser-based Indentation)
* doc/lispref/parsing.texi (Tree-sitter major modes): Update manual.

doc/lispref/modes.texi
doc/lispref/parsing.texi
lisp/progmodes/c-ts-mode.el
lisp/progmodes/java-ts-mode.el
lisp/progmodes/js.el
lisp/progmodes/ts-mode.el
lisp/treesit.el

index 8b20bc0b758c333292738e0b97bee047a78dc570..5e5eb4589742bc814f655303b0bec7d056960796 100644 (file)
@@ -4964,6 +4964,12 @@ first child where parent is @code{argument_list}, use
 (match nil "argument_list" nil nil 0 0)
 @end example
 
+@item comment-end
+This matcher is a function of 3 arguments: @var{node}, @var{parent},
+and @var{bol}, and returns non-@code{nil} if point is before a comment
+ending token.  Comment ending tokens are defined by regular expression
+@code{treesit-comment-end}.
+
 @item first-sibling
 This anchor is a function that is called with 3 arguments: @var{node},
 @var{parent}, and @var{bol}, and returns the start of the first child
@@ -4996,8 +5002,22 @@ charater on the previous line.
 This anchor is a function is called with 3 arguments: @var{node},
 @var{parent}, and @var{bol}, and returns the beginning of the buffer.
 This is useful as the beginning of the buffer is always at column 0.
-@end ftable
 
+@item comment-start
+This anchor is a function is called with 3 arguments: @var{node},
+@var{parent}, and @var{bol}, and returns the position right after the
+opening comment token.  Opening comment tokens are defined by regular
+expression @code{treesit-comment-start}.  This function assumes
+@var{parent} is the comment node.
+
+@item coment-start-skip
+This anchor is a function is called with 3 arguments: @var{node},
+@var{parent}, and @var{bol}, and returns the position after the
+opening comment token, after skipping forward any whitespace
+characters.  Opening comment tokens are defined by regular expression
+@code{treesit-comment-start}.  This function assumes @var{parent} is
+the comment node.
+@end ftable
 @end defvar
 
 @heading Indentation utilities
index feb92345ff4a2e59909da0cb1e6f1779e468743e..6a23b0feb3344be6df101b5322cb16ff1204d62f 100644 (file)
@@ -1731,6 +1731,20 @@ For more information of these built-in tree-sitter features,
 For supporting mixing of multiple languages in a major mode,
 @pxref{Multiple Languages}.
 
+Setting the following local variables allows tree-sitter's indentation
+engine to correctly indent multi-line comments:
+
+@defvar treesit-comment-start
+This should be a regular expression matching an opening comment token.
+For example, it should match @samp{//}, @samp{////}, @samp{/*},
+@samp{/****}, etc., in C.
+@end defvar
+
+@defvar treesit-comment-end
+This should be a regular expression matching an closing comment token.
+For example, it should match @samp{*/}, @samp{****/}, etc., in C.
+@end defvar
+
 @node Tree-sitter C API
 @section Tree-sitter C API Correspondence
 
index f8e809bb43f5ff96c19219d921d12915e69fe68a..43668a56d960018d775a1c5183eeb87cc7410696 100644 (file)
@@ -84,8 +84,8 @@ MODE is either `c' or `cpp'."
            ((node-is "else") parent-bol 0)
            ((node-is "case") parent-bol 0)
            ((node-is "preproc_arg") no-indent)
-           ((node-is "comment") no-indent)
-           ((parent-is "comment") no-indent)
+           ((and (parent-is "comment") comment-end) comment-start -1)
+           ((parent-is "comment") comment-start-skip 0)
            ((node-is "labeled_statement") parent-bol 0)
            ((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
            ((match "preproc_ifdef" "compound_statement") point-min 0)
@@ -503,6 +503,8 @@ the subtrees."
   (setq-local comment-start "/* ")
   (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
   (setq-local comment-end " */")
+  (setq-local treesit-comment-start (rx "/" (or (+ "/") (+ "*"))))
+  (setq-local treesit-comment-end (rx (+ (or "*")) "/"))
 
   (setq-local treesit-simple-indent-rules
               (c-ts-mode--set-indent-style 'c))
index ee7575302794c2f689f4c01887ae9e3f4c9775dd..d3cae1dcca1fee4d10a1bd183b9a1cb04d360252 100644 (file)
@@ -61,6 +61,8 @@
      ((node-is "}") (and parent parent-bol) 0)
      ((node-is ")") parent-bol 0)
      ((node-is "]") parent-bol 0)
+     ((and (parent-is "comment") comment-end) comment-start -1)
+     ((parent-is "comment") comment-start-skip 0)
      ((parent-is "class_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)
@@ -284,6 +286,8 @@ the subtrees."
   (setq-local comment-start "// ")
   (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
   (setq-local comment-end "")
+  (setq-local treesit-comment-start (rx "/" (or (+ "/") (+ "*"))))
+  (setq-local treesit-comment-end (rx (+ (or "*")) "/"))
 
   ;; Indent.
   (setq-local treesit-simple-indent-rules java-ts-mode--indent-rules)
index c37cef977b235c5c40f5ae3a2a9ec7d639bdc544..159c32ca2ae25087acc398a223a68bddcafeefbc 100644 (file)
@@ -3412,6 +3412,9 @@ This function is intended for use in `after-change-functions'."
        ((node-is ")") parent-bol 0)
        ((node-is "]") parent-bol 0)
        ((node-is ">") parent-bol 0)
+       ((parent-is "comment") comment-start 0)
+       ((and (parent-is "comment") comment-end) comment-start -1)
+       ((parent-is "comment") comment-start-skip 0)
        ((parent-is "ternary_expression") parent-bol js-indent-level)
        ((parent-is "member_expression") parent-bol js-indent-level)
        ((node-is ,switch-case) parent-bol 0)
@@ -3807,6 +3810,8 @@ Currently there are `js-mode' and `js-ts-mode'."
     (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
     (setq-local comment-end "")
     (setq-local comment-multi-line t)
+    (setq-local treesit-comment-start (rx "/" (or (+ "/") (+ "*"))))
+    (setq-local treesit-comment-end (rx (+ (or "*")) "/"))
     ;; Electric-indent.
     (setq-local electric-indent-chars
                (append "{}():;," electric-indent-chars)) ;FIXME: js2-mode adds "[]*".
index c826302c7ac6fd3ec391f758fc53fc07ec8b206b..a6f8e0a65eebe872ba76e25380010a28dbecce2e 100644 (file)
@@ -61,6 +61,8 @@
      ((node-is ")") parent-bol 0)
      ((node-is "]") parent-bol 0)
      ((node-is ">") parent-bol 0)
+     ((and (parent-is "comment") comment-end) comment-start -1)
+     ((parent-is "comment") comment-start-skip 0)
      ((parent-is "ternary_expression") parent-bol ts-mode-indent-offset)
      ((parent-is "member_expression") parent-bol ts-mode-indent-offset)
      ((parent-is "named_imports") parent-bol ts-mode-indent-offset)
     (setq-local comment-start "// ")
     (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
     (setq-local comment-end "")
+    (setq-local treesit-comment-start (rx "/" (or (+ "/") (+ "*"))))
+    (setq-local treesit-comment-end (rx (+ (or "*")) "/"))
 
     ;; Electric
     (setq-local electric-indent-chars
index 2ee977152240e554830fdab9a95c83465ca028a0..0c98d3167d98a55730217a88f41467aec3cfa46c 100644 (file)
@@ -851,6 +851,16 @@ parser notifying of the change."
 
 ;;; Indent
 
+;; `comment-start' and `comment-end' assumes there is only one type of
+;; comment and comment spans only one line.  So they are not
+;; sufficient for our purpose.
+
+(defvar-local treesit-comment-start nil
+  "Regular expression matching an opening comment token.")
+
+(defvar-local treesit-comment-end nil
+  "Regular expression matching an closing comment token.")
+
 (define-error 'treesit-indent-error
               "Generic tree-sitter indentation error"
               'treesit-error)
@@ -936,6 +946,8 @@ See `treesit-simple-indent-presets'.")
                           (lambda (node &rest _)
                             (string-match-p
                              name (or (treesit-node-field-name node) "")))))
+        (cons 'comment-end (lambda (&rest _)
+                             (looking-at-p treesit-comment-end)))
         ;; TODO: Document.
         (cons 'catch-all (lambda (&rest _) t))
 
@@ -957,6 +969,19 @@ See `treesit-simple-indent-presets'.")
                                 (treesit-node-child parent n named)))))
         (cons 'parent (lambda (_n parent &rest _)
                         (treesit-node-start parent)))
+        (cons 'comment-start
+              (lambda (_n parent &rest _)
+                (save-excursion
+                  (goto-char (treesit-node-start parent))
+                  (re-search-forward treesit-comment-start)
+                  (point))))
+        (cons 'comment-start-skip
+              (lambda (_n parent &rest _)
+                (save-excursion
+                  (goto-char (treesit-node-start parent))
+                  (re-search-forward treesit-comment-start)
+                  (skip-syntax-forward "-")
+                  (point))))
         ;; TODO: Document.
         (cons 'grand-parent
               (lambda (_n parent &rest _)
@@ -1036,6 +1061,10 @@ no-node
     Queries PARENT with QUERY, and checks if NODE is
     captured (by any capture name).
 
+comment-end
+
+    Matches if text after point matches `treesit-comment-end'.
+
 ANCHOR:
 
 first-sibling
@@ -1065,7 +1094,18 @@ prev-line
 
 point-min
 
-    Returns the beginning of buffer, which is always at column 0.")
+    Returns the beginning of buffer, which is always at column 0.
+
+comment-start
+
+    Returns the ending position after matching `treesit-comment-start'.
+    Assuming PARENT is a comment node.
+
+comment-start-skip
+
+    Goes to the position comment-start would return, skip
+    whitespaces forward, and return the resulting position.
+    Assuming PARENT is a comment node.")
 
 (defun treesit--simple-indent-eval (exp)
   "Evaluate EXP.