diff options
| author | Po Lu | 2023-01-30 21:19:55 +0800 |
|---|---|---|
| committer | Po Lu | 2023-01-30 21:19:55 +0800 |
| commit | 46e8ab23eaeb5e453042f430fc016cf9ffc2ac37 (patch) | |
| tree | e01b8db7b92c7e823b0957f4c3cd5db7a68fef23 /lisp/progmodes | |
| parent | f69583941c873506b017bd5f5a81a3dfe15d7e22 (diff) | |
| parent | 3f069bd796b0024033640051b5f74ba9834985f8 (diff) | |
| download | emacs-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.el | 118 | ||||
| -rw-r--r-- | lisp/progmodes/c-ts-mode.el | 204 | ||||
| -rw-r--r-- | lisp/progmodes/dockerfile-ts-mode.el | 20 | ||||
| -rw-r--r-- | lisp/progmodes/java-ts-mode.el | 1 | ||||
| -rw-r--r-- | lisp/progmodes/python.el | 4 | ||||
| -rw-r--r-- | lisp/progmodes/rust-ts-mode.el | 26 |
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. |
| 45 | Matches if there is a \"*\" after BOL." | 58 | Matches 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 | |||
| 263 | This should be the symbol of the indent offset variable for the | ||
| 264 | particular major mode. This cannot be nil for `c-ts-common' | ||
| 265 | statement 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 | |||
| 270 | This cannot be nil for `c-ts-common' statement indent functions | ||
| 271 | to work.") | ||
| 272 | |||
| 273 | (defvar c-ts-common-indent-bracketless-type-regexp nil | ||
| 274 | "A regexp matching types of bracketless constructs. | ||
| 275 | |||
| 276 | These constructs include if, while, do-while, for statements. In | ||
| 277 | these statements, the body can omit the bracket, which requires | ||
| 278 | special handling from our bracket-counting indent algorithm. | ||
| 279 | |||
| 280 | This 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 | |||
| 285 | This function basically counts the number of block nodes (i.e., | ||
| 286 | brackets) (defined by `c-ts-mode--indent-block-type-regexp') | ||
| 287 | between NODE and the root node (not counting NODE itself), and | ||
| 288 | multiply that by `c-ts-common-indent-offset'. | ||
| 289 | |||
| 290 | To support GNU style, on each block level, this function also | ||
| 291 | checks whether the opening bracket { is on its own line, if so, | ||
| 292 | it adds an extra level, except for the top-level. | ||
| 293 | |||
| 294 | PARENT 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. | ||
| 338 | This fixes indentation for cases shown in bug#61026. Basically | ||
| 339 | in C-like syntax, statements like if, for, while sometimes omit | ||
| 340 | the 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. | ||
| 354 | It's basically one level less that the statements in the block. | ||
| 355 | PARENT 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'. | ||
| 92 | Apart from setting the default value of SYM to VAL, also change | ||
| 93 | the 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 | |||
| 100 | set instead. This function is expected return a list that | 117 | set instead. This function is expected return a list that |
| 101 | follows the form of `treesit-simple-indent-rules'." | 118 | follows 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. | ||
| 130 | MODE 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 | |||
| 140 | This changes the current indent style of every C/C++ buffer and | ||
| 141 | the 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. | ||
| 254 | MODE 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. |
| 267 | NODE should be a labeled_statement." | 294 | NODE 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 | |||
| 285 | This is a function that takes two arguments, the current indent | ||
| 286 | level and the current node, and returns a new level. | ||
| 287 | |||
| 288 | When `c-ts-mode--statement-offset' runs and go up the parse tree, | ||
| 289 | it increments the indent level when some condition are met in | ||
| 290 | each level. At each level, after (possibly) incrementing the | ||
| 291 | offset, it calls this function, passing it the current indent | ||
| 292 | level and the current node, and use the return value as the new | ||
| 293 | indent 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 | |||
| 298 | This function basically counts the number of block nodes (defined | ||
| 299 | by `c-ts-mode--indent-block-type-regexp') between NODE and the | ||
| 300 | root node (not counting NODE itself), and multiply that by | ||
| 301 | `c-ts-mode-indent-offset'. | ||
| 302 | |||
| 303 | To support GNU style, on each block level, this function also | ||
| 304 | checks whether the opening bracket { is on its own line, if so, | ||
| 305 | it adds an extra level, except for the top-level. | ||
| 306 | |||
| 307 | PARENT 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. | ||
| 343 | This fixes indentation for cases shown in bug#61026. Basically | ||
| 344 | in C/C++, constructs like if, for, while sometimes don't have | ||
| 345 | bracket." | ||
| 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. | ||
| 355 | It's basically one level less that the statements in the block. | ||
| 356 | PARENT 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 | ||
| 65 | continuation 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 | ||
| 282 | when used for types, they should be considered pairs. | ||
| 283 | |||
| 284 | This function checks for < and > in the changed RANGES and apply | ||
| 285 | appropriate text property to alter the syntax of template | ||
| 286 | delimiters < 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 | ||