aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes
diff options
context:
space:
mode:
authorPo Lu2023-01-30 21:19:55 +0800
committerPo Lu2023-01-30 21:19:55 +0800
commit46e8ab23eaeb5e453042f430fc016cf9ffc2ac37 (patch)
treee01b8db7b92c7e823b0957f4c3cd5db7a68fef23 /lisp/progmodes
parentf69583941c873506b017bd5f5a81a3dfe15d7e22 (diff)
parent3f069bd796b0024033640051b5f74ba9834985f8 (diff)
downloademacs-46e8ab23eaeb5e453042f430fc016cf9ffc2ac37.tar.gz
emacs-46e8ab23eaeb5e453042f430fc016cf9ffc2ac37.zip
Merge remote-tracking branch 'origin/master' into feature/android
Diffstat (limited to 'lisp/progmodes')
-rw-r--r--lisp/progmodes/c-ts-common.el118
-rw-r--r--lisp/progmodes/c-ts-mode.el204
-rw-r--r--lisp/progmodes/dockerfile-ts-mode.el20
-rw-r--r--lisp/progmodes/java-ts-mode.el1
-rw-r--r--lisp/progmodes/python.el4
-rw-r--r--lisp/progmodes/rust-ts-mode.el26
6 files changed, 241 insertions, 132 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 @@
2 2
3;; Copyright (C) 2023 Free Software Foundation, Inc. 3;; Copyright (C) 2023 Free Software Foundation, Inc.
4 4
5;; Author : 付禹安 (Yuan Fu) <casouri@gmail.com> 5;; Maintainer : 付禹安 (Yuan Fu) <casouri@gmail.com>
6;; Keywords : c c++ java javascript rust languages tree-sitter 6;; Keywords : c c++ java javascript rust languages tree-sitter
7 7
8;; This file is part of GNU Emacs. 8;; This file is part of GNU Emacs.
@@ -22,7 +22,10 @@
22 22
23;;; Commentary: 23;;; Commentary:
24;; 24;;
25;; For C-like language major modes: 25;; This file contains functions that can be shared by C-like language
26;; major modes, like indenting and filling "/* */" block comments.
27;;
28;; For indenting and filling comments:
26;; 29;;
27;; - Use `c-ts-common-comment-setup' to setup comment variables and 30;; - Use `c-ts-common-comment-setup' to setup comment variables and
28;; filling. 31;; filling.
@@ -30,6 +33,14 @@
30;; - Use simple-indent matcher `c-ts-common-looking-at-star' and 33;; - Use simple-indent matcher `c-ts-common-looking-at-star' and
31;; anchor `c-ts-common-comment-start-after-first-star' for indenting 34;; anchor `c-ts-common-comment-start-after-first-star' for indenting
32;; block comments. See `c-ts-mode--indent-styles' for example. 35;; block comments. See `c-ts-mode--indent-styles' for example.
36;;
37;; For indenting statements:
38;;
39;; - Set `c-ts-common-indent-offset',
40;; `c-ts-common-indent-block-type-regexp', and
41;; `c-ts-common-indent-bracketless-type-regexp', then use simple-indent
42;; offset `c-ts-common-statement-offset' in
43;; `treesit-simple-indent-rules'.
33 44
34;;; Code: 45;;; Code:
35 46
@@ -40,6 +51,8 @@
40(declare-function treesit-node-end "treesit.c") 51(declare-function treesit-node-end "treesit.c")
41(declare-function treesit-node-type "treesit.c") 52(declare-function treesit-node-type "treesit.c")
42 53
54;;; Comment indentation and filling
55
43(defun c-ts-common-looking-at-star (_n _p bol &rest _) 56(defun c-ts-common-looking-at-star (_n _p bol &rest _)
44 "A tree-sitter simple indent matcher. 57 "A tree-sitter simple indent matcher.
45Matches if there is a \"*\" after BOL." 58Matches if there is a \"*\" after BOL."
@@ -242,6 +255,107 @@ Set up:
242 (setq-local paragraph-separate paragraph-start) 255 (setq-local paragraph-separate paragraph-start)
243 (setq-local fill-paragraph-function #'c-ts-common--fill-paragraph)) 256 (setq-local fill-paragraph-function #'c-ts-common--fill-paragraph))
244 257
258;;; Statement indent
259
260(defvar c-ts-common-indent-offset nil
261 "Indent offset used by `c-ts-common' indent functions.
262
263This should be the symbol of the indent offset variable for the
264particular major mode. This cannot be nil for `c-ts-common'
265statement indent functions to work.")
266
267(defvar c-ts-common-indent-block-type-regexp nil
268 "Regexp matching types of block nodes (i.e., {} blocks).
269
270This cannot be nil for `c-ts-common' statement indent functions
271to work.")
272
273(defvar c-ts-common-indent-bracketless-type-regexp nil
274 "A regexp matching types of bracketless constructs.
275
276These constructs include if, while, do-while, for statements. In
277these statements, the body can omit the bracket, which requires
278special handling from our bracket-counting indent algorithm.
279
280This can be nil, meaning such special handling is not needed.")
281
282(defun c-ts-common-statement-offset (node parent &rest _)
283 "This anchor is used for children of a statement inside a block.
284
285This function basically counts the number of block nodes (i.e.,
286brackets) (defined by `c-ts-mode--indent-block-type-regexp')
287between NODE and the root node (not counting NODE itself), and
288multiply that by `c-ts-common-indent-offset'.
289
290To support GNU style, on each block level, this function also
291checks whether the opening bracket { is on its own line, if so,
292it adds an extra level, except for the top-level.
293
294PARENT is NODE's parent."
295 (let ((level 0))
296 ;; If point is on an empty line, NODE would be nil, but we pretend
297 ;; there is a statement node.
298 (when (null node)
299 (setq node t))
300 ;; If NODE is a opening bracket on its own line, take off one
301 ;; level because the code below assumes NODE is a statement
302 ;; _inside_ a {} block.
303 (when (string-match-p c-ts-common-indent-block-type-regexp
304 (treesit-node-type node))
305 (cl-decf level))
306 ;; Go up the tree and compute indent level.
307 (while (if (eq node t)
308 (setq node parent)
309 node)
310 (when (string-match-p c-ts-common-indent-block-type-regexp
311 (treesit-node-type node))
312 (cl-incf level)
313 (save-excursion
314 (goto-char (treesit-node-start node))
315 ;; Add an extra level if the opening bracket is on its own
316 ;; line, except (1) it's at top-level, or (2) it's immediate
317 ;; parent is another block.
318 (cond ((bolp) nil) ; Case (1).
319 ((let ((parent-type (treesit-node-type
320 (treesit-node-parent node))))
321 ;; Case (2).
322 (and parent-type
323 (or (string-match-p
324 c-ts-common-indent-block-type-regexp
325 parent-type))))
326 nil)
327 ;; Add a level.
328 ((looking-back (rx bol (* whitespace))
329 (line-beginning-position))
330 (cl-incf level)))))
331 (setq level (c-ts-mode--fix-bracketless-indent level node))
332 ;; Go up the tree.
333 (setq node (treesit-node-parent node)))
334 (* level (symbol-value c-ts-common-indent-offset))))
335
336(defun c-ts-mode--fix-bracketless-indent (level node)
337 "Takes LEVEL and NODE and return adjusted LEVEL.
338This fixes indentation for cases shown in bug#61026. Basically
339in C-like syntax, statements like if, for, while sometimes omit
340the bracket in the body."
341 (let ((block-re c-ts-common-indent-block-type-regexp)
342 (statement-re
343 c-ts-common-indent-bracketless-type-regexp)
344 (node-type (treesit-node-type node))
345 (parent-type (treesit-node-type (treesit-node-parent node))))
346 (if (and block-re statement-re node-type parent-type
347 (not (string-match-p block-re node-type))
348 (string-match-p statement-re parent-type))
349 (1+ level)
350 level)))
351
352(defun c-ts-mode--close-bracket-offset (node parent &rest _)
353 "Offset for the closing bracket, NODE.
354It's basically one level less that the statements in the block.
355PARENT is NODE's parent."
356 (- (c-ts-common-statement-offset node parent)
357 (symbol-value c-ts-common-indent-offset)))
358
245(provide 'c-ts-common) 359(provide 'c-ts-common)
246 360
247;;; c-ts-common.el ends here 361;;; c-ts-common.el ends here
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 76ac92ed82d..8e9852ed4ee 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -63,11 +63,6 @@
63;; will set up Emacs to use the C/C++ modes defined here for other 63;; will set up Emacs to use the C/C++ modes defined here for other
64;; files, provided that you have the corresponding parser grammar 64;; files, provided that you have the corresponding parser grammar
65;; libraries installed. 65;; libraries installed.
66;;
67;; - Use variable `c-ts-mode-indent-block-type-regexp' with indent
68;; offset c-ts-mode--statement-offset for indenting statements.
69;; Again, see `c-ts-mode--indent-styles' for example.
70;;
71 66
72;;; Code: 67;;; Code:
73 68
@@ -92,6 +87,28 @@
92 :safe 'integerp 87 :safe 'integerp
93 :group 'c) 88 :group 'c)
94 89
90(defun c-ts-mode--indent-style-setter (sym val)
91 "Custom setter for `c-ts-mode-set-style'.
92Apart from setting the default value of SYM to VAL, also change
93the value of SYM in `c-ts-mode' and `c++-ts-mode' buffers to VAL."
94 (set-default sym val)
95 (named-let loop ((res nil)
96 (buffers (buffer-list)))
97 (if (null buffers)
98 (mapc (lambda (b)
99 (with-current-buffer b
100 (setq-local treesit-simple-indent-rules
101 (treesit--indent-rules-optimize
102 (c-ts-mode--get-indent-style
103 (if (eq major-mode 'c-ts-mode) 'c 'cpp))))))
104 res)
105 (let ((buffer (car buffers)))
106 (with-current-buffer buffer
107 ;; FIXME: Should we use `derived-mode-p' here?
108 (if (or (eq major-mode 'c-ts-mode) (eq major-mode 'c++-ts-mode))
109 (loop (append res (list buffer)) (cdr buffers))
110 (loop res (cdr buffers))))))))
111
95(defcustom c-ts-mode-indent-style 'gnu 112(defcustom c-ts-mode-indent-style 'gnu
96 "Style used for indentation. 113 "Style used for indentation.
97 114
@@ -100,13 +117,42 @@ one of the supplied styles doesn't suffice a function could be
100set instead. This function is expected return a list that 117set instead. This function is expected return a list that
101follows the form of `treesit-simple-indent-rules'." 118follows the form of `treesit-simple-indent-rules'."
102 :version "29.1" 119 :version "29.1"
103 :type '(choice (symbol :tag "Gnu" 'gnu) 120 :type '(choice (symbol :tag "Gnu" gnu)
104 (symbol :tag "K&R" 'k&r) 121 (symbol :tag "K&R" k&r)
105 (symbol :tag "Linux" 'linux) 122 (symbol :tag "Linux" linux)
106 (symbol :tag "BSD" 'bsd) 123 (symbol :tag "BSD" bsd)
107 (function :tag "A function for user customized style" ignore)) 124 (function :tag "A function for user customized style" ignore))
125 :set #'c-ts-mode--indent-style-setter
108 :group 'c) 126 :group 'c)
109 127
128(defun c-ts-mode--get-indent-style (mode)
129 "Helper function to set indentation style.
130MODE is either `c' or `cpp'."
131 (let ((style
132 (if (functionp c-ts-mode-indent-style)
133 (funcall c-ts-mode-indent-style)
134 (alist-get c-ts-mode-indent-style (c-ts-mode--indent-styles mode)))))
135 `((,mode ,@style))))
136
137(defun c-ts-mode-set-style ()
138 "Set the indent style of C/C++ modes globally.
139
140This changes the current indent style of every C/C++ buffer and
141the default C/C++ indent style in this Emacs session."
142 (interactive)
143 ;; FIXME: Should we use `derived-mode-p' here?
144 (or (eq major-mode 'c-ts-mode) (eq major-mode 'c++-ts-mode)
145 (error "Buffer %s is not a c-ts-mode (c-ts-mode-set-style)"
146 (buffer-name)))
147 (c-ts-mode--indent-style-setter
148 'c-ts-mode-indent-style
149 ;; NOTE: We can probably use the interactive form for this.
150 (intern
151 (completing-read
152 "Select style: "
153 (mapcar #'car (c-ts-mode--indent-styles (if (eq major-mode 'c-ts-mode) 'c 'cpp)))
154 nil t nil nil "gnu"))))
155
110;;; Syntax table 156;;; Syntax table
111 157
112(defvar c-ts-mode--syntax-table 158(defvar c-ts-mode--syntax-table
@@ -177,7 +223,7 @@ MODE is either `c' or `cpp'."
177 ;; Labels. 223 ;; Labels.
178 ((node-is "labeled_statement") parent-bol 0) 224 ((node-is "labeled_statement") parent-bol 0)
179 ((parent-is "labeled_statement") 225 ((parent-is "labeled_statement")
180 point-min c-ts-mode--statement-offset) 226 point-min c-ts-common-statement-offset)
181 227
182 ((match "preproc_ifdef" "compound_statement") point-min 0) 228 ((match "preproc_ifdef" "compound_statement") point-min 0)
183 ((match "#endif" "preproc_ifdef") point-min 0) 229 ((match "#endif" "preproc_ifdef") point-min 0)
@@ -186,15 +232,6 @@ MODE is either `c' or `cpp'."
186 ((match "preproc_function_def" "compound_statement") point-min 0) 232 ((match "preproc_function_def" "compound_statement") point-min 0)
187 ((match "preproc_call" "compound_statement") point-min 0) 233 ((match "preproc_call" "compound_statement") point-min 0)
188 234
189 ;; {} blocks.
190 ((node-is "}") point-min c-ts-mode--close-bracket-offset)
191 ((parent-is "compound_statement")
192 point-min c-ts-mode--statement-offset)
193 ((parent-is "enumerator_list")
194 point-min c-ts-mode--statement-offset)
195 ((parent-is "field_declaration_list")
196 point-min c-ts-mode--statement-offset)
197
198 ((parent-is "function_definition") parent-bol 0) 235 ((parent-is "function_definition") parent-bol 0)
199 ((parent-is "conditional_expression") first-sibling 0) 236 ((parent-is "conditional_expression") first-sibling 0)
200 ((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset) 237 ((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset)
@@ -215,13 +252,16 @@ MODE is either `c' or `cpp'."
215 ;; Indent the body of namespace definitions. 252 ;; Indent the body of namespace definitions.
216 ((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset))) 253 ((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset)))
217 254
255 ;; int[5] a = { 0, 0, 0, 0 };
218 ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset) 256 ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset)
219 ((parent-is "if_statement") parent-bol c-ts-mode-indent-offset) 257 ((parent-is "enumerator_list") point-min c-ts-common-statement-offset)
220 ((parent-is "for_statement") parent-bol c-ts-mode-indent-offset) 258 ((parent-is "field_declaration_list") point-min c-ts-common-statement-offset)
221 ((parent-is "while_statement") parent-bol c-ts-mode-indent-offset) 259
222 ((parent-is "switch_statement") parent-bol c-ts-mode-indent-offset) 260 ;; {} blocks.
223 ((parent-is "case_statement") parent-bol c-ts-mode-indent-offset) 261 ((node-is "}") point-min c-ts-mode--close-bracket-offset)
224 ((parent-is "do_statement") parent-bol c-ts-mode-indent-offset) 262 ((parent-is "compound_statement") point-min c-ts-common-statement-offset)
263 ((node-is "compound_statement") point-min c-ts-common-statement-offset)
264
225 ,@(when (eq mode 'cpp) 265 ,@(when (eq mode 'cpp)
226 `(((node-is "field_initializer_list") parent-bol ,(* c-ts-mode-indent-offset 2))))))) 266 `(((node-is "field_initializer_list") parent-bol ,(* c-ts-mode-indent-offset 2)))))))
227 `((gnu 267 `((gnu
@@ -249,19 +289,6 @@ MODE is either `c' or `cpp'."
249 ((parent-is "do_statement") parent-bol 0) 289 ((parent-is "do_statement") parent-bol 0)
250 ,@common)))) 290 ,@common))))
251 291
252(defun c-ts-mode--set-indent-style (mode)
253 "Helper function to set indentation style.
254MODE is either `c' or `cpp'."
255 (let ((style
256 (if (functionp c-ts-mode-indent-style)
257 (funcall c-ts-mode-indent-style)
258 (pcase c-ts-mode-indent-style
259 ('gnu (alist-get 'gnu (c-ts-mode--indent-styles mode)))
260 ('k&r (alist-get 'k&r (c-ts-mode--indent-styles mode)))
261 ('bsd (alist-get 'bsd (c-ts-mode--indent-styles mode)))
262 ('linux (alist-get 'linux (c-ts-mode--indent-styles mode)))))))
263 `((,mode ,@style))))
264
265(defun c-ts-mode--top-level-label-matcher (node &rest _) 292(defun c-ts-mode--top-level-label-matcher (node &rest _)
266 "A matcher that matches a top-level label. 293 "A matcher that matches a top-level label.
267NODE should be a labeled_statement." 294NODE should be a labeled_statement."
@@ -273,90 +300,6 @@ NODE should be a labeled_statement."
273 "labeled_statement") 300 "labeled_statement")
274 (not (treesit-node-top-level func "compound_statement"))))) 301 (not (treesit-node-top-level func "compound_statement")))))
275 302
276(defvar c-ts-mode-indent-block-type-regexp
277 (rx (or "compound_statement"
278 "field_declaration_list"
279 "enumerator_list"))
280 "Regexp matching types of block nodes (i.e., {} blocks).")
281
282(defvar c-ts-mode--statement-offset-post-processr nil
283 "A functions that makes adjustments to `c-ts-mode--statement-offset'.
284
285This is a function that takes two arguments, the current indent
286level and the current node, and returns a new level.
287
288When `c-ts-mode--statement-offset' runs and go up the parse tree,
289it increments the indent level when some condition are met in
290each level. At each level, after (possibly) incrementing the
291offset, it calls this function, passing it the current indent
292level and the current node, and use the return value as the new
293indent level.")
294
295(defun c-ts-mode--statement-offset (node parent &rest _)
296 "This anchor is used for children of a statement inside a block.
297
298This function basically counts the number of block nodes (defined
299by `c-ts-mode--indent-block-type-regexp') between NODE and the
300root node (not counting NODE itself), and multiply that by
301`c-ts-mode-indent-offset'.
302
303To support GNU style, on each block level, this function also
304checks whether the opening bracket { is on its own line, if so,
305it adds an extra level, except for the top-level.
306
307PARENT is NODE's parent."
308 (let ((level 0))
309 ;; If point is on an empty line, NODE would be nil, but we pretend
310 ;; there is a statement node.
311 (when (null node)
312 (setq node t))
313 (while (if (eq node t)
314 (setq node parent)
315 (setq node (treesit-node-parent node)))
316 (when (string-match-p c-ts-mode-indent-block-type-regexp
317 (treesit-node-type node))
318 (cl-incf level)
319 (save-excursion
320 (goto-char (treesit-node-start node))
321 ;; Add an extra level if the opening bracket is on its own
322 ;; line, except (1) it's at top-level, or (2) it's immediate
323 ;; parent is another block.
324 (cond ((bolp) nil) ; Case (1).
325 ((let ((parent-type (treesit-node-type
326 (treesit-node-parent node))))
327 ;; Case (2).
328 (and parent-type
329 (string-match-p c-ts-mode-indent-block-type-regexp
330 parent-type)))
331 nil)
332 ;; Add a level.
333 ((looking-back (rx bol (* whitespace))
334 (line-beginning-position))
335 (cl-incf level)))))
336 (when c-ts-mode--statement-offset-post-processr
337 (setq level (funcall c-ts-mode--statement-offset-post-processr
338 level node))))
339 (* level c-ts-mode-indent-offset)))
340
341(defun c-ts-mode--fix-bracketless-indent (level node)
342 "Takes LEVEL and NODE and returns adjusted LEVEL.
343This fixes indentation for cases shown in bug#61026. Basically
344in C/C++, constructs like if, for, while sometimes don't have
345bracket."
346 (if (and (not (equal (treesit-node-type node) "compound_statement"))
347 (member (treesit-node-type (treesit-node-parent node))
348 '("if_statement" "while_statement" "do_statement"
349 "for_statement")))
350 (1+ level)
351 level))
352
353(defun c-ts-mode--close-bracket-offset (node parent &rest _)
354 "Offset for the closing bracket, NODE.
355It's basically one level less that the statements in the block.
356PARENT is NODE's parent."
357 (- (c-ts-mode--statement-offset node parent)
358 c-ts-mode-indent-offset))
359
360;;; Font-lock 303;;; Font-lock
361 304
362(defvar c-ts-mode--preproc-keywords 305(defvar c-ts-mode--preproc-keywords
@@ -757,7 +700,8 @@ the semicolon. This function skips the semicolon."
757(defvar-keymap c-ts-mode-map 700(defvar-keymap c-ts-mode-map
758 :doc "Keymap for the C language with tree-sitter" 701 :doc "Keymap for the C language with tree-sitter"
759 :parent prog-mode-map 702 :parent prog-mode-map
760 "C-c C-q" #'c-ts-mode-indent-defun) 703 "C-c C-q" #'c-ts-mode-indent-defun
704 "C-c ." #'c-ts-mode-set-style)
761 705
762;;;###autoload 706;;;###autoload
763(define-derived-mode c-ts-base-mode prog-mode "C" 707(define-derived-mode c-ts-base-mode prog-mode "C"
@@ -817,8 +761,14 @@ the semicolon. This function skips the semicolon."
817 ;; Indent. 761 ;; Indent.
818 (when (eq c-ts-mode-indent-style 'linux) 762 (when (eq c-ts-mode-indent-style 'linux)
819 (setq-local indent-tabs-mode t)) 763 (setq-local indent-tabs-mode t))
820 (setq-local c-ts-mode--statement-offset-post-processr 764 (setq-local c-ts-common-indent-offset 'c-ts-mode-indent-offset)
821 #'c-ts-mode--fix-bracketless-indent) 765 (setq-local c-ts-common-indent-block-type-regexp
766 (rx (or "compound_statement"
767 "field_declaration_list"
768 "enumerator_list")))
769 (setq-local c-ts-common-indent-bracketless-type-regexp
770 (rx (or "if_statement" "do_statement"
771 "for_statement" "while_statement")))
822 772
823 ;; Comment 773 ;; Comment
824 (c-ts-common-comment-setup) 774 (c-ts-common-comment-setup)
@@ -871,7 +821,7 @@ in your configuration."
871 (setq-local comment-end " */") 821 (setq-local comment-end " */")
872 ;; Indent. 822 ;; Indent.
873 (setq-local treesit-simple-indent-rules 823 (setq-local treesit-simple-indent-rules
874 (c-ts-mode--set-indent-style 'c)) 824 (c-ts-mode--get-indent-style 'c))
875 ;; Font-lock. 825 ;; Font-lock.
876 (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c)) 826 (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
877 (treesit-major-mode-setup))) 827 (treesit-major-mode-setup)))
@@ -907,7 +857,7 @@ in your configuration."
907 857
908 ;; Indent. 858 ;; Indent.
909 (setq-local treesit-simple-indent-rules 859 (setq-local treesit-simple-indent-rules
910 (c-ts-mode--set-indent-style 'cpp)) 860 (c-ts-mode--get-indent-style 'cpp))
911 861
912 ;; Font-lock. 862 ;; Font-lock.
913 (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) 863 (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el
index 23ac48a6117..c9125bc6cbd 100644
--- a/lisp/progmodes/dockerfile-ts-mode.el
+++ b/lisp/progmodes/dockerfile-ts-mode.el
@@ -51,9 +51,27 @@
51 ((parent-is "expose_instruction") (nth-sibling 1) 0) 51 ((parent-is "expose_instruction") (nth-sibling 1) 0)
52 ((parent-is "label_instruction") (nth-sibling 1) 0) 52 ((parent-is "label_instruction") (nth-sibling 1) 0)
53 ((parent-is "shell_command") first-sibling 0) 53 ((parent-is "shell_command") first-sibling 0)
54 ((parent-is "string_array") first-sibling 1))) 54 ((parent-is "string_array") first-sibling 1)
55 ((dockerfile-ts-mode--line-continuation-p) dockerfile-ts-mode--line-continuation-anchor 0)))
55 "Tree-sitter indent rules.") 56 "Tree-sitter indent rules.")
56 57
58(defun dockerfile-ts-mode--line-continuation-p ()
59 "Return t if the current node is a line continuation node."
60 (lambda (node _ _ &rest _)
61 (string= (treesit-node-type node) "\n")))
62
63(defun dockerfile-ts-mode--line-continuation-anchor (_ _ &rest _)
64 "This anchor is used to align any nodes that are part of a line
65continuation to the previous entry."
66 (save-excursion
67 (forward-line -1)
68 (let ((prev-node (treesit-node-at (point))))
69 (if (string= (treesit-node-type prev-node) "\\\n")
70 (back-to-indentation)
71 (forward-word)
72 (forward-char))
73 (+ 1 (- (point) (pos-bol))))))
74
57(defvar dockerfile-ts-mode--keywords 75(defvar dockerfile-ts-mode--keywords
58 '("ADD" "ARG" "AS" "CMD" "COPY" "CROSS_BUILD" "ENTRYPOINT" "ENV" 76 '("ADD" "ARG" "AS" "CMD" "COPY" "CROSS_BUILD" "ENTRYPOINT" "ENV"
59 "EXPOSE" "FROM" "HEALTHCHECK" "LABEL" "MAINTAINER" "ONBUILD" "RUN" 77 "EXPOSE" "FROM" "HEALTHCHECK" "LABEL" "MAINTAINER" "ONBUILD" "RUN"
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index dbd63698770..e4153725efd 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -89,6 +89,7 @@
89 ((query "(method_declaration (block (_) @indent))") parent-bol java-ts-mode-indent-offset) 89 ((query "(method_declaration (block (_) @indent))") parent-bol java-ts-mode-indent-offset)
90 ((parent-is "local_variable_declaration") parent-bol java-ts-mode-indent-offset) 90 ((parent-is "local_variable_declaration") parent-bol java-ts-mode-indent-offset)
91 ((parent-is "expression_statement") parent-bol java-ts-mode-indent-offset) 91 ((parent-is "expression_statement") parent-bol java-ts-mode-indent-offset)
92 ((match "type_identifier" "field_declaration") parent-bol 0)
92 ((parent-is "field_declaration") parent-bol java-ts-mode-indent-offset) 93 ((parent-is "field_declaration") parent-bol java-ts-mode-indent-offset)
93 ((parent-is "return_statement") parent-bol java-ts-mode-indent-offset) 94 ((parent-is "return_statement") parent-bol java-ts-mode-indent-offset)
94 ((parent-is "variable_declarator") parent-bol java-ts-mode-indent-offset) 95 ((parent-is "variable_declarator") parent-bol java-ts-mode-indent-offset)
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index a869cdc5fdb..df0d1c96965 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -6715,8 +6715,8 @@ implementations: `python-mode' and `python-ts-mode'."
6715 (when python-indent-guess-indent-offset 6715 (when python-indent-guess-indent-offset
6716 (python-indent-guess-indent-offset)) 6716 (python-indent-guess-indent-offset))
6717 6717
6718 (add-to-list 'auto-mode-alist 6718 (add-to-list 'auto-mode-alist '("\\.py[iw]?\\'" . python-ts-mode))
6719 '("\\.py[iw]?\\'\\|python[0-9.]*" . python-ts-mode)))) 6719 (add-to-list 'interpreter-mode-alist '("python[0-9.]*" . python-ts-mode))))
6720 6720
6721;;; Completion predicates for M-x 6721;;; Completion predicates for M-x
6722;; Commands that only make sense when editing Python code 6722;; Commands that only make sense when editing Python code
diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el
index 3a6cb61b719..2812e39c101 100644
--- a/lisp/progmodes/rust-ts-mode.el
+++ b/lisp/progmodes/rust-ts-mode.el
@@ -275,6 +275,28 @@ Return nil if there is no name or if NODE is not a defun node."
275 (treesit-node-text 275 (treesit-node-text
276 (treesit-node-child-by-field-name node "name") t)))) 276 (treesit-node-child-by-field-name node "name") t))))
277 277
278(defun rust-ts-mode--syntax-propertize (beg end)
279 "Apply syntax text property to template delimiters between BEG and END.
280
281< and > are usually punctuation, e.g., as greater/less-than. But
282when used for types, they should be considered pairs.
283
284This function checks for < and > in the changed RANGES and apply
285appropriate text property to alter the syntax of template
286delimiters < and >'s."
287 (goto-char beg)
288 (while (re-search-forward (rx (or "<" ">")) end t)
289 (pcase (treesit-node-type
290 (treesit-node-parent
291 (treesit-node-at (match-beginning 0))))
292 ("type_arguments"
293 (put-text-property (match-beginning 0)
294 (match-end 0)
295 'syntax-table
296 (pcase (char-before)
297 (?< '(4 . ?>))
298 (?> '(5 . ?<))))))))
299
278;;;###autoload 300;;;###autoload
279(define-derived-mode rust-ts-mode prog-mode "Rust" 301(define-derived-mode rust-ts-mode prog-mode "Rust"
280 "Major mode for editing Rust, powered by tree-sitter." 302 "Major mode for editing Rust, powered by tree-sitter."
@@ -284,6 +306,10 @@ Return nil if there is no name or if NODE is not a defun node."
284 (when (treesit-ready-p 'rust) 306 (when (treesit-ready-p 'rust)
285 (treesit-parser-create 'rust) 307 (treesit-parser-create 'rust)
286 308
309 ;; Syntax.
310 (setq-local syntax-propertize-function
311 #'rust-ts-mode--syntax-propertize)
312
287 ;; Comments. 313 ;; Comments.
288 (c-ts-common-comment-setup) 314 (c-ts-common-comment-setup)
289 315