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 | |
| parent | f69583941c873506b017bd5f5a81a3dfe15d7e22 (diff) | |
| parent | 3f069bd796b0024033640051b5f74ba9834985f8 (diff) | |
| download | emacs-46e8ab23eaeb5e453042f430fc016cf9ffc2ac37.tar.gz emacs-46e8ab23eaeb5e453042f430fc016cf9ffc2ac37.zip | |
Merge remote-tracking branch 'origin/master' into feature/android
| -rw-r--r-- | doc/emacs/display.texi | 131 | ||||
| -rw-r--r-- | doc/emacs/emacs.texi | 4 | ||||
| -rw-r--r-- | doc/emacs/files.texi | 11 | ||||
| -rw-r--r-- | doc/emacs/frames.texi | 1 | ||||
| -rw-r--r-- | doc/emacs/misc.texi | 6 | ||||
| -rw-r--r-- | doc/emacs/programs.texi | 42 | ||||
| -rw-r--r-- | doc/emacs/text.texi | 12 | ||||
| -rw-r--r-- | doc/lispref/variables.texi | 1 | ||||
| -rw-r--r-- | etc/NEWS.29 | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 44 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 50 | ||||
| -rw-r--r-- | lisp/emacs-lisp/comp.el | 7 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 4 | ||||
| -rw-r--r-- | lisp/org/org-agenda.el | 8 | ||||
| -rw-r--r-- | lisp/org/org-macs.el | 2 | ||||
| -rw-r--r-- | lisp/org/org-version.el | 2 | ||||
| -rw-r--r-- | lisp/org/org.el | 1 | ||||
| -rw-r--r-- | lisp/org/ox.el | 4 | ||||
| -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 | ||||
| -rw-r--r-- | lisp/treesit.el | 107 | ||||
| -rw-r--r-- | src/comp.c | 3 | ||||
| -rw-r--r-- | src/treesit.c | 63 | ||||
| -rw-r--r-- | test/lisp/progmodes/c-ts-mode-resources/indent.erts | 8 |
28 files changed, 640 insertions, 250 deletions
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index f77ab569483..97732b65e32 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi | |||
| @@ -1024,17 +1024,65 @@ customize-group @key{RET} font-lock-faces @key{RET}}. You can then | |||
| 1024 | use that customization buffer to customize the appearance of these | 1024 | use that customization buffer to customize the appearance of these |
| 1025 | faces. @xref{Face Customization}. | 1025 | faces. @xref{Face Customization}. |
| 1026 | 1026 | ||
| 1027 | @cindex just-in-time (JIT) font-lock | ||
| 1028 | @cindex background syntax highlighting | ||
| 1029 | Fontifying very large buffers can take a long time. To avoid large | ||
| 1030 | delays when a file is visited, Emacs initially fontifies only the | ||
| 1031 | visible portion of a buffer. As you scroll through the buffer, each | ||
| 1032 | portion that becomes visible is fontified as soon as it is displayed; | ||
| 1033 | this type of Font Lock is called @dfn{Just-In-Time} (or @dfn{JIT}) | ||
| 1034 | Lock. You can control how JIT Lock behaves, including telling it to | ||
| 1035 | perform fontification while idle, by customizing variables in the | ||
| 1036 | customization group @samp{jit-lock}. @xref{Specific Customization}. | ||
| 1037 | |||
| 1038 | The information that major modes use for determining which parts of | ||
| 1039 | buffer text to fontify and what faces to use can be based on several | ||
| 1040 | different ways of analyzing the text: | ||
| 1041 | |||
| 1042 | @itemize @bullet | ||
| 1043 | @item | ||
| 1044 | Search for keywords and other textual patterns based on regular | ||
| 1045 | expressions (@pxref{Regexp Search,, Regular Expression Search}). | ||
| 1046 | |||
| 1047 | @item | ||
| 1048 | Find syntactically distinct parts of text based on built-in syntax | ||
| 1049 | tables (@pxref{Syntax Tables,,, elisp, The Emacs Lisp Reference | ||
| 1050 | Manual}). | ||
| 1051 | |||
| 1052 | @item | ||
| 1053 | Use syntax tree produced by a full-blown parser, via a special-purpose | ||
| 1054 | library, such as the tree-sitter library (@pxref{Parsing Program | ||
| 1055 | Source,,, elisp, The Emacs Lisp Reference Manual}), or an external | ||
| 1056 | program. | ||
| 1057 | @end itemize | ||
| 1058 | |||
| 1059 | @menu | ||
| 1060 | * Traditional Font Lock:: Font Lock based on regexps and syntax tables. | ||
| 1061 | * Parser-based Font Lock:: Font Lock based on external parser. | ||
| 1062 | @end menu | ||
| 1063 | |||
| 1064 | @node Traditional Font Lock | ||
| 1065 | @subsection Traditional Font Lock | ||
| 1066 | @cindex traditional font-lock | ||
| 1067 | |||
| 1068 | ``Traditional'' methods of providing font-lock information are based | ||
| 1069 | on regular-expression search and on syntactic analysis using syntax | ||
| 1070 | tables built into Emacs. This subsection describes the use and | ||
| 1071 | customization of font-lock for major modes which use these traditional | ||
| 1072 | methods. | ||
| 1073 | |||
| 1027 | @vindex font-lock-maximum-decoration | 1074 | @vindex font-lock-maximum-decoration |
| 1028 | You can customize the variable @code{font-lock-maximum-decoration} | 1075 | You can control the amount of fontification applied by Font Lock |
| 1029 | to alter the amount of fontification applied by Font Lock mode, for | 1076 | mode by customizing the variable @code{font-lock-maximum-decoration}, |
| 1030 | major modes that support this feature. The value should be a number | 1077 | for major modes that support this feature. The value of this variable |
| 1031 | (with 1 representing a minimal amount of fontification; some modes | 1078 | should be a number (with 1 representing a minimal amount of |
| 1032 | support levels as high as 3); or @code{t}, meaning ``as high as | 1079 | fontification; some modes support levels as high as 3); or @code{t}, |
| 1033 | possible'' (the default). To be effective for a given file buffer, | 1080 | meaning ``as high as possible'' (the default). To be effective for a |
| 1034 | the customization of @code{font-lock-maximum-decoration} should be | 1081 | given file buffer, the customization of |
| 1035 | done @emph{before} the file is visited; if you already have the file | 1082 | @code{font-lock-maximum-decoration} should be done @emph{before} the |
| 1036 | visited in a buffer when you customize this variable, kill the buffer | 1083 | file is visited; if you already have the file visited in a buffer when |
| 1037 | and visit the file again after the customization. | 1084 | you customize this variable, kill the buffer and visit the file again |
| 1085 | after the customization. | ||
| 1038 | 1086 | ||
| 1039 | You can also specify different numbers for particular major modes; for | 1087 | You can also specify different numbers for particular major modes; for |
| 1040 | example, to use level 1 for C/C++ modes, and the default level | 1088 | example, to use level 1 for C/C++ modes, and the default level |
| @@ -1082,16 +1130,59 @@ keywords by customizing the @code{font-lock-ignore} option, | |||
| 1082 | @pxref{Customizing Keywords,,, elisp, The Emacs Lisp Reference | 1130 | @pxref{Customizing Keywords,,, elisp, The Emacs Lisp Reference |
| 1083 | Manual}. | 1131 | Manual}. |
| 1084 | 1132 | ||
| 1085 | @cindex just-in-time (JIT) font-lock | 1133 | @node Parser-based Font Lock |
| 1086 | @cindex background syntax highlighting | 1134 | @subsection Parser-based Font Lock |
| 1087 | Fontifying large buffers can take a long time. To avoid large | 1135 | @cindex font-lock via tree-sitter |
| 1088 | delays when a file is visited, Emacs initially fontifies only the | 1136 | @cindex parser-based font-lock |
| 1089 | visible portion of a buffer. As you scroll through the buffer, each | 1137 | If your Emacs was built with the tree-sitter library, it can use the |
| 1090 | portion that becomes visible is fontified as soon as it is displayed; | 1138 | results of parsing the buffer text by that library for the purposes of |
| 1091 | this type of Font Lock is called @dfn{Just-In-Time} (or @dfn{JIT}) | 1139 | fontification. This is usually faster and more accurate than the |
| 1092 | Lock. You can control how JIT Lock behaves, including telling it to | 1140 | ``traditional'' methods described in the previous subsection, since |
| 1093 | perform fontification while idle, by customizing variables in the | 1141 | the tree-sitter library provides full-blown parsers for programming |
| 1094 | customization group @samp{jit-lock}. @xref{Specific Customization}. | 1142 | languages and other kinds of formatted text which it supports. Major |
| 1143 | modes which utilize the tree-sitter library are named | ||
| 1144 | @code{@var{foo}-ts-mode}, with the @samp{-ts-} part indicating the use | ||
| 1145 | of the library. This subsection documents the Font Lock support based | ||
| 1146 | on the tree-sitter library. | ||
| 1147 | |||
| 1148 | @vindex treesit-font-lock-level | ||
| 1149 | You can control the amount of fontification applied by Font Lock | ||
| 1150 | mode of major modes based on tree-sitter by customizing the variable | ||
| 1151 | @code{treesit-font-lock-level}. Its value is a number between 1 and | ||
| 1152 | 4: | ||
| 1153 | |||
| 1154 | @table @asis | ||
| 1155 | @item Level 1 | ||
| 1156 | This level usually fontifies only comments and function names in | ||
| 1157 | function definitions. | ||
| 1158 | @item Level 2 | ||
| 1159 | This level adds fontification of keywords, strings, and data types. | ||
| 1160 | @item Level 3 | ||
| 1161 | This is the default level; it adds fontification of assignments, | ||
| 1162 | numbers, properties, etc. | ||
| 1163 | @item Level 4 | ||
| 1164 | This level adds everything else that can be fontified: operators, | ||
| 1165 | delimiters, brackets, other punctuation, function names in function | ||
| 1166 | calls, variables, etc. | ||
| 1167 | @end table | ||
| 1168 | |||
| 1169 | @vindex treesit-font-lock-feature-list | ||
| 1170 | @noindent | ||
| 1171 | What exactly constitutes each of the syntactical categories mentioned | ||
| 1172 | above depends on the major mode and the parser grammar used by | ||
| 1173 | tree-sitter for the major-mode's language. However, in general the | ||
| 1174 | categories follow the conventions of the programming language or the | ||
| 1175 | file format supported by the major mode. The buffer-local value of | ||
| 1176 | the variable @code{treesit-font-lock-feature-list} holds the | ||
| 1177 | fontification features supported by a tree-sitter based major mode, | ||
| 1178 | where each sub-list shows the features provided by the corresponding | ||
| 1179 | fontification level. | ||
| 1180 | |||
| 1181 | Once you change the value of @code{treesit-font-lock-level} via | ||
| 1182 | @w{@kbd{M-x customize-variable}} (@pxref{Specific Customization}), it | ||
| 1183 | takes effect immediately in all the existing buffers and for files you | ||
| 1184 | visit in the future in the same session. | ||
| 1185 | |||
| 1095 | 1186 | ||
| 1096 | @node Highlight Interactively | 1187 | @node Highlight Interactively |
| 1097 | @section Interactive Highlighting | 1188 | @section Interactive Highlighting |
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 30758efb43a..59e7f5bb64b 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi | |||
| @@ -385,6 +385,10 @@ Controlling the Display | |||
| 385 | * Visual Line Mode:: Word wrap and screen line-based editing. | 385 | * Visual Line Mode:: Word wrap and screen line-based editing. |
| 386 | * Display Custom:: Information on variables for customizing display. | 386 | * Display Custom:: Information on variables for customizing display. |
| 387 | 387 | ||
| 388 | Font Lock | ||
| 389 | * Traditional Font Lock:: Font Lock based on regexps and syntax tables. | ||
| 390 | * Parser-based Font Lock:: Font Lock based on external parser. | ||
| 391 | |||
| 388 | Searching and Replacement | 392 | Searching and Replacement |
| 389 | 393 | ||
| 390 | * Incremental Search:: Search happens as you type the string. | 394 | * Incremental Search:: Search happens as you type the string. |
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index 42e252c417b..664b9d5d9a3 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi | |||
| @@ -215,6 +215,17 @@ by the integers that Emacs can represent (@pxref{Buffers}). If you | |||
| 215 | try, Emacs displays an error message saying that the maximum buffer | 215 | try, Emacs displays an error message saying that the maximum buffer |
| 216 | size has been exceeded. | 216 | size has been exceeded. |
| 217 | 217 | ||
| 218 | @vindex treesit-max-buffer-size | ||
| 219 | If you try to visit a file whose major mode (@pxref{Major Modes}) | ||
| 220 | uses the tree-sitter parsing library, Emacs will display a warning if | ||
| 221 | the file's size in bytes is larger than the value of the variable | ||
| 222 | @code{treesit-max-buffer-size}. The default value is 40 megabytes for | ||
| 223 | 64-bit Emacs and 15 megabytes for 32-bit Emacs. This avoids the | ||
| 224 | danger of having Emacs run out of memory by preventing the activation | ||
| 225 | of major modes based on tree-sitter in such large buffers, because a | ||
| 226 | typical tree-sitter parser needs about 10 times as much memory as the | ||
| 227 | text it parses. | ||
| 228 | |||
| 218 | @cindex wildcard characters in file names | 229 | @cindex wildcard characters in file names |
| 219 | @vindex find-file-wildcards | 230 | @vindex find-file-wildcards |
| 220 | If the file name you specify contains shell-style wildcard | 231 | If the file name you specify contains shell-style wildcard |
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi index 3ee6eb59dbb..ce631561be7 100644 --- a/doc/emacs/frames.texi +++ b/doc/emacs/frames.texi | |||
| @@ -334,6 +334,7 @@ In this way, you can use the mouse to move point over a button without | |||
| 334 | activating it. Dragging the mouse over or onto a button has its usual | 334 | activating it. Dragging the mouse over or onto a button has its usual |
| 335 | behavior of setting the region, and does not activate the button. | 335 | behavior of setting the region, and does not activate the button. |
| 336 | 336 | ||
| 337 | @vindex mouse-1-click-follows-link | ||
| 337 | You can change how @kbd{mouse-1} applies to buttons by customizing | 338 | You can change how @kbd{mouse-1} applies to buttons by customizing |
| 338 | the variable @code{mouse-1-click-follows-link}. If the value is a | 339 | the variable @code{mouse-1-click-follows-link}. If the value is a |
| 339 | positive integer, that determines how long you need to hold the mouse | 340 | positive integer, that determines how long you need to hold the mouse |
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 3ee8ee5ee39..a5e1689b6c7 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi | |||
| @@ -470,11 +470,7 @@ documents. It provides features such as slicing, zooming, and | |||
| 470 | searching inside documents. It works by converting the document to a | 470 | searching inside documents. It works by converting the document to a |
| 471 | set of images using the @command{gs} (GhostScript) or | 471 | set of images using the @command{gs} (GhostScript) or |
| 472 | @command{pdfdraw}/@command{mutool draw} (MuPDF) commands and other | 472 | @command{pdfdraw}/@command{mutool draw} (MuPDF) commands and other |
| 473 | external tools @footnote{PostScript files require GhostScript, DVI | 473 | external tools, and then displays those converted images. |
| 474 | files require @code{dvipdf} or @code{dvipdfm}, OpenDocument and | ||
| 475 | Microsoft Office documents require the @code{unoconv} tool, and EPUB, | ||
| 476 | CBZ, FB2, XPS and OXPS files require @code{mutool} to be available.}, | ||
| 477 | and displaying those images. | ||
| 478 | 474 | ||
| 479 | @findex doc-view-toggle-display | 475 | @findex doc-view-toggle-display |
| 480 | @findex doc-view-minor-mode | 476 | @findex doc-view-minor-mode |
diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index 065ed1c51f7..d983c2b59c6 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi | |||
| @@ -255,6 +255,17 @@ they do their standard jobs in a way better fitting a particular | |||
| 255 | language. Other major modes may replace any or all of these key | 255 | language. Other major modes may replace any or all of these key |
| 256 | bindings for that purpose. | 256 | bindings for that purpose. |
| 257 | 257 | ||
| 258 | @cindex nested defuns | ||
| 259 | @vindex treesit-defun-tactic | ||
| 260 | Some programming languages supported @dfn{nested defuns}, whereby a | ||
| 261 | defun (such as a function or a method or a class) can be defined | ||
| 262 | inside (i.e., as part of the body) of another defun. The commands | ||
| 263 | described above by default find the beginning and the end of the | ||
| 264 | @emph{innermost} defun around point. Major modes based on the | ||
| 265 | tree-sitter library provide control of this behavior: if the variable | ||
| 266 | @code{treesit-defun-tactic} is set to the value @code{top-level}, the | ||
| 267 | defun commands will find the @emph{outermost} defuns instead. | ||
| 268 | |||
| 258 | @node Moving by Sentences | 269 | @node Moving by Sentences |
| 259 | @subsection Moving by Sentences | 270 | @subsection Moving by Sentences |
| 260 | @cindex sentences, in programming languages | 271 | @cindex sentences, in programming languages |
| @@ -599,15 +610,19 @@ then indent it like this: | |||
| 599 | @item C-c C-q | 610 | @item C-c C-q |
| 600 | @kindex C-c C-q @r{(C mode)} | 611 | @kindex C-c C-q @r{(C mode)} |
| 601 | @findex c-indent-defun | 612 | @findex c-indent-defun |
| 613 | @findex c-ts-mode-indent-defun | ||
| 602 | Reindent the current top-level function definition or aggregate type | 614 | Reindent the current top-level function definition or aggregate type |
| 603 | declaration (@code{c-indent-defun}). | 615 | declaration (@code{c-indent-defun} in CC mode, |
| 616 | @code{c-ts-mode-indent-defun} in @code{c-ts-mode} based on tree-sitter). | ||
| 604 | 617 | ||
| 605 | @item C-M-q | 618 | @item C-M-q |
| 606 | @kindex C-M-q @r{(C mode)} | 619 | @kindex C-M-q @r{(C mode)} |
| 607 | @findex c-indent-exp | 620 | @findex c-indent-exp |
| 608 | Reindent each line in the balanced expression that follows point | 621 | @findex prog-indent-sexp |
| 609 | (@code{c-indent-exp}). A prefix argument inhibits warning messages | 622 | Reindent each line in the balanced expression that follows point. In |
| 610 | about invalid syntax. | 623 | CC mode, this invokes @code{c-indent-exp}; in tree-sitter based |
| 624 | @code{c-ts-mode} this invokes a more general @code{prog-indent-sexp}. | ||
| 625 | A prefix argument inhibits warning messages about invalid syntax. | ||
| 611 | 626 | ||
| 612 | @item @key{TAB} | 627 | @item @key{TAB} |
| 613 | @findex c-indent-line-or-region | 628 | @findex c-indent-line-or-region |
| @@ -647,7 +662,8 @@ onto the indentation of the @dfn{anchor statement}. | |||
| 647 | 662 | ||
| 648 | @table @kbd | 663 | @table @kbd |
| 649 | @item C-c . @var{style} @key{RET} | 664 | @item C-c . @var{style} @key{RET} |
| 650 | Select a predefined style @var{style} (@code{c-set-style}). | 665 | Select a predefined style @var{style} (@code{c-set-style} in CC mode, |
| 666 | @code{c-ts-mode-set-style} in @code{c-ts-mode} based on tree-sitter). | ||
| 651 | @end table | 667 | @end table |
| 652 | 668 | ||
| 653 | A @dfn{style} is a named collection of customizations that can be | 669 | A @dfn{style} is a named collection of customizations that can be |
| @@ -663,6 +679,7 @@ typing @kbd{C-M-q} at the start of a function definition. | |||
| 663 | 679 | ||
| 664 | @kindex C-c . @r{(C mode)} | 680 | @kindex C-c . @r{(C mode)} |
| 665 | @findex c-set-style | 681 | @findex c-set-style |
| 682 | @findex c-ts-mode-set-style | ||
| 666 | To choose a style for the current buffer, use the command @w{@kbd{C-c | 683 | To choose a style for the current buffer, use the command @w{@kbd{C-c |
| 667 | .}}. Specify a style name as an argument (case is not significant). | 684 | .}}. Specify a style name as an argument (case is not significant). |
| 668 | This command affects the current buffer only, and it affects only | 685 | This command affects the current buffer only, and it affects only |
| @@ -671,11 +688,11 @@ the code already in the buffer. To reindent the whole buffer in the | |||
| 671 | new style, you can type @kbd{C-x h C-M-\}. | 688 | new style, you can type @kbd{C-x h C-M-\}. |
| 672 | 689 | ||
| 673 | @vindex c-default-style | 690 | @vindex c-default-style |
| 674 | You can also set the variable @code{c-default-style} to specify the | 691 | When using CC mode, you can also set the variable |
| 675 | default style for various major modes. Its value should be either the | 692 | @code{c-default-style} to specify the default style for various major |
| 676 | style's name (a string) or an alist, in which each element specifies | 693 | modes. Its value should be either the style's name (a string) or an |
| 677 | one major mode and which indentation style to use for it. For | 694 | alist, in which each element specifies one major mode and which |
| 678 | example, | 695 | indentation style to use for it. For example, |
| 679 | 696 | ||
| 680 | @example | 697 | @example |
| 681 | (setq c-default-style | 698 | (setq c-default-style |
| @@ -692,6 +709,11 @@ one of the C-like major modes; thus, if you specify a new default | |||
| 692 | style for Java mode, you can make it take effect in an existing Java | 709 | style for Java mode, you can make it take effect in an existing Java |
| 693 | mode buffer by typing @kbd{M-x java-mode} there. | 710 | mode buffer by typing @kbd{M-x java-mode} there. |
| 694 | 711 | ||
| 712 | @vindex c-ts-mode-indent-style | ||
| 713 | When using the tree-sitter based @code{c-ts-mode}, you can set the | ||
| 714 | default indentation style by customizing the variable | ||
| 715 | @code{c-ts-mode-indent-style}. | ||
| 716 | |||
| 695 | The @code{gnu} style specifies the formatting recommended by the GNU | 717 | The @code{gnu} style specifies the formatting recommended by the GNU |
| 696 | Project for C; it is the default, so as to encourage use of our | 718 | Project for C; it is the default, so as to encourage use of our |
| 697 | recommended style. | 719 | recommended style. |
diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 78e89d8031a..18f2274cfa6 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi | |||
| @@ -1021,14 +1021,16 @@ this variable is @code{insert}, the buttons are inserted directly into | |||
| 1021 | the buffer text, so @key{RET} on the button will also toggle display | 1021 | the buffer text, so @key{RET} on the button will also toggle display |
| 1022 | of the section, like a mouse click does. If the value is | 1022 | of the section, like a mouse click does. If the value is |
| 1023 | @code{in-margins}, Outline minor mode will use the window margins to | 1023 | @code{in-margins}, Outline minor mode will use the window margins to |
| 1024 | indicate that a section is hidden. | 1024 | indicate that a section is hidden. The buttons are customizable as icons |
| 1025 | (@pxref{Icons}). | ||
| 1025 | 1026 | ||
| 1026 | @vindex outline-minor-mode-cycle | 1027 | @vindex outline-minor-mode-cycle |
| 1027 | If the @code{outline-minor-mode-cycle} user option is | 1028 | If the @code{outline-minor-mode-cycle} user option is |
| 1028 | non-@code{nil}, the @kbd{TAB} and @kbd{S-@key{TAB}} keys are enabled on the | 1029 | non-@code{nil}, the @kbd{TAB} and @kbd{S-@key{TAB}} keys that cycle |
| 1029 | outline heading lines. @kbd{TAB} cycles hiding, showing the | 1030 | the visibility are enabled on the outline heading lines |
| 1030 | sub-heading, and showing all for the current section. @kbd{S-@key{TAB}} | 1031 | (@pxref{Outline Visibility, outline-cycle}). @kbd{TAB} cycles hiding, |
| 1031 | does the same for the entire buffer. | 1032 | showing the sub-heading, and showing all for the current section. |
| 1033 | @kbd{S-@key{TAB}} does the same for the entire buffer. | ||
| 1032 | 1034 | ||
| 1033 | @node Outline Format | 1035 | @node Outline Format |
| 1034 | @subsection Format of Outlines | 1036 | @subsection Format of Outlines |
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 39d0906f6c4..5584cbce9a6 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi | |||
| @@ -2023,6 +2023,7 @@ file-local variables stored in @code{file-local-variables-alist}. | |||
| 2023 | @end defvar | 2023 | @end defvar |
| 2024 | 2024 | ||
| 2025 | @cindex safe local variable | 2025 | @cindex safe local variable |
| 2026 | @cindex @code{safe-local-variable}, property of variable | ||
| 2026 | You can specify safe values for a variable with a | 2027 | You can specify safe values for a variable with a |
| 2027 | @code{safe-local-variable} property. The property has to be a | 2028 | @code{safe-local-variable} property. The property has to be a |
| 2028 | function of one argument; any value is safe if the function returns | 2029 | function of one argument; any value is safe if the function returns |
diff --git a/etc/NEWS.29 b/etc/NEWS.29 index 4d199676848..fb211f9b7d0 100644 --- a/etc/NEWS.29 +++ b/etc/NEWS.29 | |||
| @@ -1018,6 +1018,8 @@ quotes removed. | |||
| 1018 | 1018 | ||
| 1019 | --- | 1019 | --- |
| 1020 | *** 'M-x apropos-variable' output now includes values of variables. | 1020 | *** 'M-x apropos-variable' output now includes values of variables. |
| 1021 | Such apropos buffer is more easily viewed with outlining after | ||
| 1022 | enabling 'outline-minor-mode' in 'apropos-mode'. | ||
| 1021 | 1023 | ||
| 1022 | +++ | 1024 | +++ |
| 1023 | *** New docstring syntax to indicate that symbols shouldn't be links. | 1025 | *** New docstring syntax to indicate that symbols shouldn't be links. |
| @@ -2480,6 +2482,10 @@ matches. | |||
| 2480 | --- | 2482 | --- |
| 2481 | *** New function 'xref-show-xrefs'. | 2483 | *** New function 'xref-show-xrefs'. |
| 2482 | 2484 | ||
| 2485 | *** 'outline-minor-mode' is supported in Xref buffers. | ||
| 2486 | You can enable outlining by adding 'outline-minor-mode' to | ||
| 2487 | 'xref-after-update-hook'. | ||
| 2488 | |||
| 2483 | ** File Notifications | 2489 | ** File Notifications |
| 2484 | 2490 | ||
| 2485 | +++ | 2491 | +++ |
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index b1a46d520e6..4d39e28fc8e 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -975,6 +975,43 @@ for speeding up processing.") | |||
| 975 | (t ;; Moving the constant to the end can enable some lapcode optimizations. | 975 | (t ;; Moving the constant to the end can enable some lapcode optimizations. |
| 976 | (list (car form) (nth 2 form) (nth 1 form))))) | 976 | (list (car form) (nth 2 form) (nth 1 form))))) |
| 977 | 977 | ||
| 978 | (defun byte-opt--nary-comparison (form) | ||
| 979 | "Optimise n-ary comparisons such as `=', `<' etc." | ||
| 980 | (let ((nargs (length (cdr form)))) | ||
| 981 | (cond | ||
| 982 | ((= nargs 1) | ||
| 983 | `(progn (cadr form) t)) | ||
| 984 | ((>= nargs 3) | ||
| 985 | ;; At least 3 arguments: transform to N-1 binary comparisons, | ||
| 986 | ;; since those have their own byte-ops which are particularly | ||
| 987 | ;; fast for fixnums. | ||
| 988 | (let* ((op (car form)) | ||
| 989 | (bindings nil) | ||
| 990 | (rev-args nil)) | ||
| 991 | (if (memq nil (mapcar #'macroexp-copyable-p (cddr form))) | ||
| 992 | ;; At least one arg beyond the first is non-constant non-variable: | ||
| 993 | ;; create temporaries for all args to guard against side-effects. | ||
| 994 | ;; The optimiser will eliminate trivial bindings later. | ||
| 995 | (let ((i 1)) | ||
| 996 | (dolist (arg (cdr form)) | ||
| 997 | (let ((var (make-symbol (format "arg%d" i)))) | ||
| 998 | (push var rev-args) | ||
| 999 | (push (list var arg) bindings) | ||
| 1000 | (setq i (1+ i))))) | ||
| 1001 | ;; All args beyond the first are copyable: no temporary variables | ||
| 1002 | ;; required. | ||
| 1003 | (setq rev-args (reverse (cdr form)))) | ||
| 1004 | (let ((prev (car rev-args)) | ||
| 1005 | (exprs nil)) | ||
| 1006 | (dolist (arg (cdr rev-args)) | ||
| 1007 | (push (list op arg prev) exprs) | ||
| 1008 | (setq prev arg)) | ||
| 1009 | (let ((and-expr (cons 'and exprs))) | ||
| 1010 | (if bindings | ||
| 1011 | (list 'let (nreverse bindings) and-expr) | ||
| 1012 | and-expr))))) | ||
| 1013 | (t form)))) | ||
| 1014 | |||
| 978 | (defun byte-optimize-constant-args (form) | 1015 | (defun byte-optimize-constant-args (form) |
| 979 | (let ((ok t) | 1016 | (let ((ok t) |
| 980 | (rest (cdr form))) | 1017 | (rest (cdr form))) |
| @@ -1130,13 +1167,18 @@ See Info node `(elisp) Integer Basics'." | |||
| 1130 | (put 'max 'byte-optimizer #'byte-optimize-min-max) | 1167 | (put 'max 'byte-optimizer #'byte-optimize-min-max) |
| 1131 | (put 'min 'byte-optimizer #'byte-optimize-min-max) | 1168 | (put 'min 'byte-optimizer #'byte-optimize-min-max) |
| 1132 | 1169 | ||
| 1133 | (put '= 'byte-optimizer #'byte-optimize-binary-predicate) | ||
| 1134 | (put 'eq 'byte-optimizer #'byte-optimize-eq) | 1170 | (put 'eq 'byte-optimizer #'byte-optimize-eq) |
| 1135 | (put 'eql 'byte-optimizer #'byte-optimize-equal) | 1171 | (put 'eql 'byte-optimizer #'byte-optimize-equal) |
| 1136 | (put 'equal 'byte-optimizer #'byte-optimize-equal) | 1172 | (put 'equal 'byte-optimizer #'byte-optimize-equal) |
| 1137 | (put 'string= 'byte-optimizer #'byte-optimize-binary-predicate) | 1173 | (put 'string= 'byte-optimizer #'byte-optimize-binary-predicate) |
| 1138 | (put 'string-equal 'byte-optimizer #'byte-optimize-binary-predicate) | 1174 | (put 'string-equal 'byte-optimizer #'byte-optimize-binary-predicate) |
| 1139 | 1175 | ||
| 1176 | (put '= 'byte-optimizer #'byte-opt--nary-comparison) | ||
| 1177 | (put '< 'byte-optimizer #'byte-opt--nary-comparison) | ||
| 1178 | (put '<= 'byte-optimizer #'byte-opt--nary-comparison) | ||
| 1179 | (put '> 'byte-optimizer #'byte-opt--nary-comparison) | ||
| 1180 | (put '>= 'byte-optimizer #'byte-opt--nary-comparison) | ||
| 1181 | |||
| 1140 | (put 'string-greaterp 'byte-optimizer #'byte-optimize-string-greaterp) | 1182 | (put 'string-greaterp 'byte-optimizer #'byte-optimize-string-greaterp) |
| 1141 | (put 'string> 'byte-optimizer #'byte-optimize-string-greaterp) | 1183 | (put 'string> 'byte-optimizer #'byte-optimize-string-greaterp) |
| 1142 | 1184 | ||
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index aa9521e5a65..e8a8fe37756 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -3748,7 +3748,7 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" | |||
| 3748 | '((0 . byte-compile-no-args) | 3748 | '((0 . byte-compile-no-args) |
| 3749 | (1 . byte-compile-one-arg) | 3749 | (1 . byte-compile-one-arg) |
| 3750 | (2 . byte-compile-two-args) | 3750 | (2 . byte-compile-two-args) |
| 3751 | (2-and . byte-compile-and-folded) | 3751 | (2-cmp . byte-compile-cmp) |
| 3752 | (3 . byte-compile-three-args) | 3752 | (3 . byte-compile-three-args) |
| 3753 | (0-1 . byte-compile-zero-or-one-arg) | 3753 | (0-1 . byte-compile-zero-or-one-arg) |
| 3754 | (1-2 . byte-compile-one-or-two-args) | 3754 | (1-2 . byte-compile-one-or-two-args) |
| @@ -3827,11 +3827,11 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" | |||
| 3827 | (byte-defop-compiler cons 2) | 3827 | (byte-defop-compiler cons 2) |
| 3828 | (byte-defop-compiler aref 2) | 3828 | (byte-defop-compiler aref 2) |
| 3829 | (byte-defop-compiler set 2) | 3829 | (byte-defop-compiler set 2) |
| 3830 | (byte-defop-compiler (= byte-eqlsign) 2-and) | 3830 | (byte-defop-compiler (= byte-eqlsign) 2-cmp) |
| 3831 | (byte-defop-compiler (< byte-lss) 2-and) | 3831 | (byte-defop-compiler (< byte-lss) 2-cmp) |
| 3832 | (byte-defop-compiler (> byte-gtr) 2-and) | 3832 | (byte-defop-compiler (> byte-gtr) 2-cmp) |
| 3833 | (byte-defop-compiler (<= byte-leq) 2-and) | 3833 | (byte-defop-compiler (<= byte-leq) 2-cmp) |
| 3834 | (byte-defop-compiler (>= byte-geq) 2-and) | 3834 | (byte-defop-compiler (>= byte-geq) 2-cmp) |
| 3835 | (byte-defop-compiler get 2) | 3835 | (byte-defop-compiler get 2) |
| 3836 | (byte-defop-compiler nth 2) | 3836 | (byte-defop-compiler nth 2) |
| 3837 | (byte-defop-compiler substring 1-3) | 3837 | (byte-defop-compiler substring 1-3) |
| @@ -3895,18 +3895,20 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" | |||
| 3895 | (byte-compile-form (nth 2 form)) | 3895 | (byte-compile-form (nth 2 form)) |
| 3896 | (byte-compile-out (get (car form) 'byte-opcode) 0))) | 3896 | (byte-compile-out (get (car form) 'byte-opcode) 0))) |
| 3897 | 3897 | ||
| 3898 | (defun byte-compile-and-folded (form) | 3898 | (defun byte-compile-cmp (form) |
| 3899 | "Compile calls to functions like `<='. | 3899 | "Compile calls to numeric comparisons such as `<', `=' etc." |
| 3900 | These implicitly `and' together a bunch of two-arg bytecodes." | 3900 | ;; Lisp-level transforms should already have reduced valid calls to 2 args. |
| 3901 | (let ((l (length form))) | 3901 | (if (not (= (length form) 3)) |
| 3902 | (cond | 3902 | (byte-compile-subr-wrong-args form "1 or more") |
| 3903 | ((< l 3) (byte-compile-form `(progn ,(nth 1 form) t))) | 3903 | (byte-compile-two-args |
| 3904 | ((= l 3) (byte-compile-two-args form)) | 3904 | (if (macroexp-const-p (nth 1 form)) |
| 3905 | ;; Don't use `cl-every' here (see comment where we require cl-lib). | 3905 | ;; First argument is constant: flip it so that the constant |
| 3906 | ((not (memq nil (mapcar #'macroexp-copyable-p (nthcdr 2 form)))) | 3906 | ;; is last, which may allow more lapcode optimisations. |
| 3907 | (byte-compile-form `(and (,(car form) ,(nth 1 form) ,(nth 2 form)) | 3907 | (let* ((op (car form)) |
| 3908 | (,(car form) ,@(nthcdr 2 form))))) | 3908 | (flipped-op (cdr (assq op '((< . >) (<= . >=) |
| 3909 | (t (byte-compile-normal-call form))))) | 3909 | (> . <) (>= . <=) (= . =)))))) |
| 3910 | (list flipped-op (nth 2 form) (nth 1 form))) | ||
| 3911 | form)))) | ||
| 3910 | 3912 | ||
| 3911 | (defun byte-compile-three-args (form) | 3913 | (defun byte-compile-three-args (form) |
| 3912 | (if (not (= (length form) 4)) | 3914 | (if (not (= (length form) 4)) |
| @@ -4061,9 +4063,15 @@ This function is never called when `lexical-binding' is nil." | |||
| 4061 | (byte-compile-constant 1) | 4063 | (byte-compile-constant 1) |
| 4062 | (byte-compile-out (get '* 'byte-opcode) 0)) | 4064 | (byte-compile-out (get '* 'byte-opcode) 0)) |
| 4063 | (3 | 4065 | (3 |
| 4064 | (byte-compile-form (nth 1 form)) | 4066 | (let ((arg1 (nth 1 form)) |
| 4065 | (byte-compile-form (nth 2 form)) | 4067 | (arg2 (nth 2 form))) |
| 4066 | (byte-compile-out (get (car form) 'byte-opcode) 0)) | 4068 | (when (and (memq (car form) '(+ *)) |
| 4069 | (macroexp-const-p arg1)) | ||
| 4070 | ;; Put constant argument last for better LAP optimisation. | ||
| 4071 | (cl-rotatef arg1 arg2)) | ||
| 4072 | (byte-compile-form arg1) | ||
| 4073 | (byte-compile-form arg2) | ||
| 4074 | (byte-compile-out (get (car form) 'byte-opcode) 0))) | ||
| 4067 | (_ | 4075 | (_ |
| 4068 | ;; >2 args: compile as a single function call. | 4076 | ;; >2 args: compile as a single function call. |
| 4069 | (byte-compile-normal-call form)))) | 4077 | (byte-compile-normal-call form)))) |
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index 4c423be06c4..d2e7d933f4f 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el | |||
| @@ -4112,13 +4112,16 @@ the deferred compilation mechanism." | |||
| 4112 | (native-elisp-load data))) | 4112 | (native-elisp-load data))) |
| 4113 | ;; We may have created a temporary file when we're being | 4113 | ;; We may have created a temporary file when we're being |
| 4114 | ;; called with something other than a file as the argument. | 4114 | ;; called with something other than a file as the argument. |
| 4115 | ;; Delete it. | 4115 | ;; Delete it if we can. |
| 4116 | (when (and (not (stringp function-or-file)) | 4116 | (when (and (not (stringp function-or-file)) |
| 4117 | (not output) | 4117 | (not output) |
| 4118 | comp-ctxt | 4118 | comp-ctxt |
| 4119 | (comp-ctxt-output comp-ctxt) | 4119 | (comp-ctxt-output comp-ctxt) |
| 4120 | (file-exists-p (comp-ctxt-output comp-ctxt))) | 4120 | (file-exists-p (comp-ctxt-output comp-ctxt))) |
| 4121 | (delete-file (comp-ctxt-output comp-ctxt)))))))) | 4121 | (cond ((eq 'windows-nt system-type) |
| 4122 | ;; We may still be using the temporary .eln file. | ||
| 4123 | (ignore-errors (delete-file (comp-ctxt-output comp-ctxt)))) | ||
| 4124 | (t (delete-file (comp-ctxt-output comp-ctxt)))))))))) | ||
| 4122 | 4125 | ||
| 4123 | (defun native-compile-async-skip-p (file load selector) | 4126 | (defun native-compile-async-skip-p (file load selector) |
| 4124 | "Return non-nil if FILE's compilation should be skipped. | 4127 | "Return non-nil if FILE's compilation should be skipped. |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 3871ee4dddd..21dbd40b1d2 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -642,7 +642,7 @@ This regexp must match both `tramp-initial-end-of-output' and | |||
| 642 | (rx | 642 | (rx |
| 643 | bol (* nonl) | 643 | bol (* nonl) |
| 644 | (group (regexp (regexp-opt password-word-equivalents))) | 644 | (group (regexp (regexp-opt password-word-equivalents))) |
| 645 | (* nonl) ":" (? "\^@") (* blank)) | 645 | (* nonl) (any "::៖") (? "\^@") (* blank)) |
| 646 | "Regexp matching password-like prompts. | 646 | "Regexp matching password-like prompts. |
| 647 | The regexp should match at end of buffer. | 647 | The regexp should match at end of buffer. |
| 648 | 648 | ||
| @@ -652,7 +652,7 @@ usually more convenient to add new passphrases to that variable | |||
| 652 | instead of altering this variable. | 652 | instead of altering this variable. |
| 653 | 653 | ||
| 654 | The `sudo' program appears to insert a `^@' character into the prompt." | 654 | The `sudo' program appears to insert a `^@' character into the prompt." |
| 655 | :version "24.4" | 655 | :version "29.1" |
| 656 | :type 'regexp) | 656 | :type 'regexp) |
| 657 | 657 | ||
| 658 | (defcustom tramp-wrong-passwd-regexp | 658 | (defcustom tramp-wrong-passwd-regexp |
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el index 2d194ad3413..63107e8e6a4 100644 --- a/lisp/org/org-agenda.el +++ b/lisp/org/org-agenda.el | |||
| @@ -3474,13 +3474,17 @@ This ensures the export commands can easily use it." | |||
| 3474 | (when (setq tmp (plist-get props 'date)) | 3474 | (when (setq tmp (plist-get props 'date)) |
| 3475 | (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) | 3475 | (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) |
| 3476 | (let ((calendar-date-display-form | 3476 | (let ((calendar-date-display-form |
| 3477 | '(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left)))) | 3477 | '((format "%s-%.2d-%.2d" year |
| 3478 | (string-to-number month) | ||
| 3479 | (string-to-number day))))) | ||
| 3478 | (setq tmp (calendar-date-string tmp))) | 3480 | (setq tmp (calendar-date-string tmp))) |
| 3479 | (setq props (plist-put props 'date tmp))) | 3481 | (setq props (plist-put props 'date tmp))) |
| 3480 | (when (setq tmp (plist-get props 'day)) | 3482 | (when (setq tmp (plist-get props 'day)) |
| 3481 | (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) | 3483 | (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) |
| 3482 | (let ((calendar-date-display-form | 3484 | (let ((calendar-date-display-form |
| 3483 | '(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left)))) | 3485 | '((format "%s-%.2d-%.2d" year |
| 3486 | (string-to-number month) | ||
| 3487 | (string-to-number day))))) | ||
| 3484 | (setq tmp (calendar-date-string tmp))) | 3488 | (setq tmp (calendar-date-string tmp))) |
| 3485 | (setq props (plist-put props 'day tmp)) | 3489 | (setq props (plist-put props 'day tmp)) |
| 3486 | (setq props (plist-put props 'agenda-day tmp))) | 3490 | (setq props (plist-put props 'agenda-day tmp))) |
diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el index 07c668a807d..8d7b0b034f8 100644 --- a/lisp/org/org-macs.el +++ b/lisp/org/org-macs.el | |||
| @@ -46,7 +46,7 @@ | |||
| 46 | ;; `org-git-version' check because the generated Org version strings | 46 | ;; `org-git-version' check because the generated Org version strings |
| 47 | ;; will not match. | 47 | ;; will not match. |
| 48 | `(unless (equal (org-release) ,(org-release)) | 48 | `(unless (equal (org-release) ,(org-release)) |
| 49 | (warn "Org version mismatch. Make sure that correct `load-path' is set early in init.el | 49 | (warn "Org version mismatch. Org loading aborted. |
| 50 | This warning usually appears when a built-in Org version is loaded | 50 | This warning usually appears when a built-in Org version is loaded |
| 51 | prior to the more recent Org version. | 51 | prior to the more recent Org version. |
| 52 | 52 | ||
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el index 22f952d7a30..8372a0be4a5 100644 --- a/lisp/org/org-version.el +++ b/lisp/org/org-version.el | |||
| @@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made." | |||
| 11 | (defun org-git-version () | 11 | (defun org-git-version () |
| 12 | "The Git version of Org mode. | 12 | "The Git version of Org mode. |
| 13 | Inserted by installing Org or when a release is made." | 13 | Inserted by installing Org or when a release is made." |
| 14 | (let ((org-git-version "release_9.6.1-16-ge37e9b")) | 14 | (let ((org-git-version "release_9.6.1-23-gc45a05")) |
| 15 | org-git-version)) | 15 | org-git-version)) |
| 16 | 16 | ||
| 17 | (provide 'org-version) | 17 | (provide 'org-version) |
diff --git a/lisp/org/org.el b/lisp/org/org.el index 153e860f9a5..1b829d837c7 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el | |||
| @@ -8608,6 +8608,7 @@ or to another Org file, automatically push the old position onto the ring." | |||
| 8608 | (defvar org-agenda-buffer-name) | 8608 | (defvar org-agenda-buffer-name) |
| 8609 | (defun org-follow-timestamp-link () | 8609 | (defun org-follow-timestamp-link () |
| 8610 | "Open an agenda view for the time-stamp date/range at point." | 8610 | "Open an agenda view for the time-stamp date/range at point." |
| 8611 | (require 'org-agenda) | ||
| 8611 | ;; Avoid changing the global value. | 8612 | ;; Avoid changing the global value. |
| 8612 | (let ((org-agenda-buffer-name org-agenda-buffer-name)) | 8613 | (let ((org-agenda-buffer-name org-agenda-buffer-name)) |
| 8613 | (cond | 8614 | (cond |
diff --git a/lisp/org/ox.el b/lisp/org/ox.el index 65f9ff18279..6f819def93a 100644 --- a/lisp/org/ox.el +++ b/lisp/org/ox.el | |||
| @@ -6600,14 +6600,14 @@ see. | |||
| 6600 | Optional argument POST-PROCESS is a function which should accept | 6600 | Optional argument POST-PROCESS is a function which should accept |
| 6601 | no argument. It is always called within the current process, | 6601 | no argument. It is always called within the current process, |
| 6602 | from BUFFER, with point at its beginning. Export back-ends can | 6602 | from BUFFER, with point at its beginning. Export back-ends can |
| 6603 | use it to set a major mode there, e.g, | 6603 | use it to set a major mode there, e.g., |
| 6604 | 6604 | ||
| 6605 | (defun org-latex-export-as-latex | 6605 | (defun org-latex-export-as-latex |
| 6606 | (&optional async subtreep visible-only body-only ext-plist) | 6606 | (&optional async subtreep visible-only body-only ext-plist) |
| 6607 | (interactive) | 6607 | (interactive) |
| 6608 | (org-export-to-buffer \\='latex \"*Org LATEX Export*\" | 6608 | (org-export-to-buffer \\='latex \"*Org LATEX Export*\" |
| 6609 | async subtreep visible-only body-only ext-plist | 6609 | async subtreep visible-only body-only ext-plist |
| 6610 | #'LaTeX-mode)) | 6610 | #\\='LaTeX-mode)) |
| 6611 | 6611 | ||
| 6612 | When expressed as an anonymous function, using `lambda', | 6612 | When expressed as an anonymous function, using `lambda', |
| 6613 | POST-PROCESS needs to be quoted. | 6613 | POST-PROCESS needs to be quoted. |
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 | ||
diff --git a/lisp/treesit.el b/lisp/treesit.el index 29b29d2665a..c9f2e339dc2 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el | |||
| @@ -554,7 +554,25 @@ omitted, default END to BEG." | |||
| 554 | "Generic tree-sitter font-lock error" | 554 | "Generic tree-sitter font-lock error" |
| 555 | 'treesit-error) | 555 | 'treesit-error) |
| 556 | 556 | ||
| 557 | (defvar-local treesit-font-lock-level 3 | 557 | (defun treesit--font-lock-level-setter (sym val) |
| 558 | "Custom setter for `treesit-font-lock-level'." | ||
| 559 | (set-default sym val) | ||
| 560 | (named-let loop ((res nil) | ||
| 561 | (buffers (buffer-list))) | ||
| 562 | (if (null buffers) | ||
| 563 | (mapc (lambda (b) | ||
| 564 | (with-current-buffer b | ||
| 565 | (setq-local treesit-font-lock-level val) | ||
| 566 | (treesit-font-lock-recompute-features) | ||
| 567 | (treesit-font-lock-fontify-region (point-min) (point-max)))) | ||
| 568 | res) | ||
| 569 | (let ((buffer (car buffers))) | ||
| 570 | (with-current-buffer buffer | ||
| 571 | (if (treesit-parser-list) | ||
| 572 | (loop (append res (list buffer)) (cdr buffers)) | ||
| 573 | (loop res (cdr buffers)))))))) | ||
| 574 | |||
| 575 | (defcustom treesit-font-lock-level 3 | ||
| 558 | "Decoration level to be used by tree-sitter fontifications. | 576 | "Decoration level to be used by tree-sitter fontifications. |
| 559 | 577 | ||
| 560 | Major modes categorize their fontification features into levels, | 578 | Major modes categorize their fontification features into levels, |
| @@ -562,16 +580,24 @@ from 1 which is the absolute minimum, to 4 that yields the maximum | |||
| 562 | fontifications. | 580 | fontifications. |
| 563 | 581 | ||
| 564 | Level 1 usually contains only comments and definitions. | 582 | Level 1 usually contains only comments and definitions. |
| 565 | Level 2 usually adds keywords, strings, constants, types, etc. | 583 | Level 2 usually adds keywords, strings, data types, etc. |
| 566 | Level 3 usually represents a full-blown fontification, including | 584 | Level 3 usually represents full-blown fontifications, including |
| 567 | assignment, constants, numbers, properties, etc. | 585 | assignments, constants, numbers and literals, properties, etc. |
| 568 | Level 4 adds everything else that can be fontified: delimiters, | 586 | Level 4 adds everything else that can be fontified: delimiters, |
| 569 | operators, brackets, all functions and variables, etc. | 587 | operators, brackets, punctuation, all functions and variables, etc. |
| 570 | 588 | ||
| 571 | In addition to the decoration level, individual features can be | 589 | In addition to the decoration level, individual features can be |
| 572 | turned on/off by calling `treesit-font-lock-recompute-features'. | 590 | turned on/off by calling `treesit-font-lock-recompute-features'. |
| 573 | Changing the decoration level requires calling | 591 | Changing the decoration level requires calling |
| 574 | `treesit-font-lock-recompute-features' to have an effect.") | 592 | `treesit-font-lock-recompute-features' to have an effect, unless |
| 593 | done via `customize-variable'. | ||
| 594 | |||
| 595 | To see which syntactical categories are fontified by each level | ||
| 596 | in a particular major mode, examine the buffer-local value of the | ||
| 597 | variable `treesit-font-lock-feature-list'." | ||
| 598 | :type 'integer | ||
| 599 | :set #'treesit--font-lock-level-setter | ||
| 600 | :version "29.1") | ||
| 575 | 601 | ||
| 576 | (defvar-local treesit--font-lock-query-expand-range (cons 0 0) | 602 | (defvar-local treesit--font-lock-query-expand-range (cons 0 0) |
| 577 | "The amount to expand the start and end of the region when fontifying. | 603 | "The amount to expand the start and end of the region when fontifying. |
| @@ -892,27 +918,20 @@ LIMIT is the recursion limit, which defaults to 100." | |||
| 892 | (push r result)) | 918 | (push r result)) |
| 893 | (push child result)) | 919 | (push child result)) |
| 894 | (setq child (treesit-node-next-sibling child))) | 920 | (setq child (treesit-node-next-sibling child))) |
| 895 | ;; If NODE has no child, keep NODE. | 921 | ;; If NODE has no child, keep NODE. If LIMIT is exceeded, return |
| 896 | (or result (list node)))) | 922 | ;; nil. |
| 923 | (or result (and (> limit 0) (list node))))) | ||
| 897 | 924 | ||
| 898 | (defsubst treesit--node-length (node) | 925 | (defsubst treesit--node-length (node) |
| 899 | "Return the length of the text of NODE." | 926 | "Return the length of the text of NODE." |
| 900 | (- (treesit-node-end node) (treesit-node-start node))) | 927 | (- (treesit-node-end node) (treesit-node-start node))) |
| 901 | 928 | ||
| 902 | (defvar-local treesit--font-lock-fast-mode nil | 929 | (defvar-local treesit--font-lock-fast-mode 'unspecified |
| 903 | "If this variable is t, change the way we query so it's faster. | 930 | "If this variable is t, change the way we query so it's faster. |
| 904 | This is not a general optimization and should be RARELY needed! | 931 | This is not a general optimization and should be RARELY needed! |
| 905 | See comments in `treesit-font-lock-fontify-region' for more | 932 | See comments in `treesit-font-lock-fontify-region' for more |
| 906 | detail.") | 933 | detail.") |
| 907 | 934 | ||
| 908 | (defvar-local treesit--font-lock-fast-mode-grace-count 5 | ||
| 909 | "Grace counts before we turn on the fast mode. | ||
| 910 | |||
| 911 | When query takes abnormally long time to execute, we turn on the | ||
| 912 | \"fast mode\", but just to be on the safe side, we only turn on | ||
| 913 | the fast mode after this number of offenses. See bug#60691, | ||
| 914 | bug#60223.") | ||
| 915 | |||
| 916 | ;; Some details worth explaining: | 935 | ;; Some details worth explaining: |
| 917 | ;; | 936 | ;; |
| 918 | ;; 1. When we apply face to a node, we clip the face into the | 937 | ;; 1. When we apply face to a node, we clip the face into the |
| @@ -964,36 +983,34 @@ If LOUDLY is non-nil, display some debugging information." | |||
| 964 | (enable (nth 1 setting)) | 983 | (enable (nth 1 setting)) |
| 965 | (override (nth 3 setting)) | 984 | (override (nth 3 setting)) |
| 966 | (language (treesit-query-language query))) | 985 | (language (treesit-query-language query))) |
| 967 | (when-let ((nodes (list (treesit-buffer-root-node language))) | ||
| 968 | ;; Only activate if ENABLE flag is t. | ||
| 969 | (activate (eq t enable))) | ||
| 970 | (ignore activate) | ||
| 971 | 986 | ||
| 972 | ;; If we run into problematic files, use the "fast mode" to | 987 | ;; Use deterministic way to decide whether to turn on "fast |
| 973 | ;; try to recover. See comment #2 above for more explanation. | 988 | ;; mode". (See bug#60691, bug#60223.) |
| 974 | (when treesit--font-lock-fast-mode | 989 | (when (eq treesit--font-lock-fast-mode 'unspecified) |
| 975 | (setq nodes (treesit--children-covering-range-recurse | 990 | (pcase-let ((`(,max-depth ,max-width) |
| 976 | (car nodes) start end (* 4 jit-lock-chunk-size)))) | 991 | (treesit-subtree-stat |
| 992 | (treesit-buffer-root-node language)))) | ||
| 993 | (if (or (> max-depth 100) (> max-width 4000)) | ||
| 994 | (setq treesit--font-lock-fast-mode t) | ||
| 995 | (setq treesit--font-lock-fast-mode nil)))) | ||
| 996 | |||
| 997 | (when-let* ((root (treesit-buffer-root-node language)) | ||
| 998 | (nodes (if (eq t treesit--font-lock-fast-mode) | ||
| 999 | (treesit--children-covering-range-recurse | ||
| 1000 | root start end (* 4 jit-lock-chunk-size)) | ||
| 1001 | (list (treesit-buffer-root-node language)))) | ||
| 1002 | ;; Only activate if ENABLE flag is t. | ||
| 1003 | (activate (eq t enable))) | ||
| 1004 | (ignore activate) | ||
| 977 | 1005 | ||
| 978 | ;; Query each node. | 1006 | ;; Query each node. |
| 979 | (dolist (sub-node nodes) | 1007 | (dolist (sub-node nodes) |
| 980 | (let* ((delta-start (car treesit--font-lock-query-expand-range)) | 1008 | (let* ((delta-start (car treesit--font-lock-query-expand-range)) |
| 981 | (delta-end (cdr treesit--font-lock-query-expand-range)) | 1009 | (delta-end (cdr treesit--font-lock-query-expand-range)) |
| 982 | (start-time (current-time)) | ||
| 983 | (captures (treesit-query-capture | 1010 | (captures (treesit-query-capture |
| 984 | sub-node query | 1011 | sub-node query |
| 985 | (max (- start delta-start) (point-min)) | 1012 | (max (- start delta-start) (point-min)) |
| 986 | (min (+ end delta-end) (point-max)))) | 1013 | (min (+ end delta-end) (point-max))))) |
| 987 | (end-time (current-time))) | ||
| 988 | ;; If for any query the query time is strangely long, | ||
| 989 | ;; switch to fast mode (see comments above). | ||
| 990 | (when (and (null treesit--font-lock-fast-mode) | ||
| 991 | (> (time-to-seconds | ||
| 992 | (time-subtract end-time start-time)) | ||
| 993 | 0.01)) | ||
| 994 | (if (> treesit--font-lock-fast-mode-grace-count 0) | ||
| 995 | (cl-decf treesit--font-lock-fast-mode-grace-count) | ||
| 996 | (setq-local treesit--font-lock-fast-mode t))) | ||
| 997 | 1014 | ||
| 998 | ;; For each captured node, fontify that node. | 1015 | ;; For each captured node, fontify that node. |
| 999 | (with-silent-modifications | 1016 | (with-silent-modifications |
| @@ -1002,12 +1019,14 @@ If LOUDLY is non-nil, display some debugging information." | |||
| 1002 | (node (cdr capture)) | 1019 | (node (cdr capture)) |
| 1003 | (node-start (treesit-node-start node)) | 1020 | (node-start (treesit-node-start node)) |
| 1004 | (node-end (treesit-node-end node))) | 1021 | (node-end (treesit-node-end node))) |
| 1022 | |||
| 1005 | ;; If node is not in the region, take them out. See | 1023 | ;; If node is not in the region, take them out. See |
| 1006 | ;; comment #3 above for more detail. | 1024 | ;; comment #3 above for more detail. |
| 1007 | (if (and (facep face) | 1025 | (if (and (facep face) |
| 1008 | (or (>= start node-end) (>= node-start end))) | 1026 | (or (>= start node-end) (>= node-start end))) |
| 1009 | (when (or loudly treesit--font-lock-verbose) | 1027 | (when (or loudly treesit--font-lock-verbose) |
| 1010 | (message "Captured node %s(%s-%s) but it is outside of fontifing region" node node-start node-end)) | 1028 | (message "Captured node %s(%s-%s) but it is outside of fontifing region" node node-start node-end)) |
| 1029 | |||
| 1011 | (cond | 1030 | (cond |
| 1012 | ((facep face) | 1031 | ((facep face) |
| 1013 | (treesit-fontify-with-override | 1032 | (treesit-fontify-with-override |
| @@ -1015,6 +1034,7 @@ If LOUDLY is non-nil, display some debugging information." | |||
| 1015 | face override)) | 1034 | face override)) |
| 1016 | ((functionp face) | 1035 | ((functionp face) |
| 1017 | (funcall face node override start end))) | 1036 | (funcall face node override start end))) |
| 1037 | |||
| 1018 | ;; Don't raise an error if FACE is neither a face nor | 1038 | ;; Don't raise an error if FACE is neither a face nor |
| 1019 | ;; a function. This is to allow intermediate capture | 1039 | ;; a function. This is to allow intermediate capture |
| 1020 | ;; names used for #match and #eq. | 1040 | ;; names used for #match and #eq. |
| @@ -3033,10 +3053,10 @@ function signals an error." | |||
| 3033 | :no-value (treesit-parser-set-included-ranges parser '((1 . 4) (5 . 8)))) | 3053 | :no-value (treesit-parser-set-included-ranges parser '((1 . 4) (5 . 8)))) |
| 3034 | (treesit-parser-included-ranges | 3054 | (treesit-parser-included-ranges |
| 3035 | :no-eval (treesit-parser-included-ranges parser) | 3055 | :no-eval (treesit-parser-included-ranges parser) |
| 3036 | :eg-result '((1 . 4) (5 . 8))) | 3056 | :eg-result ((1 . 4) (5 . 8))) |
| 3037 | (treesit-query-range | 3057 | (treesit-query-range |
| 3038 | :no-eval (treesit-query-range node '((script_element) @cap)) | 3058 | :no-eval (treesit-query-range node '((script_element) @cap)) |
| 3039 | :eg-result-string '((1 . 4) (5 . 8))) | 3059 | :eg-result ((1 . 4) (5 . 8))) |
| 3040 | 3060 | ||
| 3041 | 3061 | ||
| 3042 | "Retrieving a node" | 3062 | "Retrieving a node" |
| @@ -3182,7 +3202,12 @@ function signals an error." | |||
| 3182 | :eg-result-string "#<treesit-node (translation_unit) in 1-11>") | 3202 | :eg-result-string "#<treesit-node (translation_unit) in 1-11>") |
| 3183 | (treesit-query-string | 3203 | (treesit-query-string |
| 3184 | :no-eval (treesit-query-string "int c = 0;" '((identifier) @id) 'c) | 3204 | :no-eval (treesit-query-string "int c = 0;" '((identifier) @id) 'c) |
| 3185 | :eg-result-string "((id . #<treesit-node (identifier) in 5-6>))")) | 3205 | :eg-result-string "((id . #<treesit-node (identifier) in 5-6>))") |
| 3206 | |||
| 3207 | "Misc" | ||
| 3208 | (treesit-subtree-stat | ||
| 3209 | :no-eval (treesit-subtree-stat node) | ||
| 3210 | :eg-result (6 33 487))) | ||
| 3186 | 3211 | ||
| 3187 | (provide 'treesit) | 3212 | (provide 'treesit) |
| 3188 | 3213 | ||
diff --git a/src/comp.c b/src/comp.c index 6ff1915ef5b..ba549155925 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -5912,6 +5912,3 @@ file -> CU. */); | |||
| 5912 | 5912 | ||
| 5913 | defsubr (&Snative_comp_available_p); | 5913 | defsubr (&Snative_comp_available_p); |
| 5914 | } | 5914 | } |
| 5915 | /* Local Variables: */ | ||
| 5916 | /* c-file-offsets: ((arglist-intro . +)) */ | ||
| 5917 | /* End: */ | ||
diff --git a/src/treesit.c b/src/treesit.c index 917db582676..b210ec0923a 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -3312,6 +3312,68 @@ a regexp. */) | |||
| 3312 | return parent; | 3312 | return parent; |
| 3313 | } | 3313 | } |
| 3314 | 3314 | ||
| 3315 | DEFUN ("treesit-subtree-stat", | ||
| 3316 | Ftreesit_subtree_stat, | ||
| 3317 | Streesit_subtree_stat, 1, 1, 0, | ||
| 3318 | doc: /* Return information about the subtree of NODE. | ||
| 3319 | |||
| 3320 | Return a list (MAX-DEPTH MAX-WIDTH COUNT), where MAX-DEPTH is the | ||
| 3321 | maximum depth of the subtree, MAX-WIDTH is the maximum number of | ||
| 3322 | direct children of nodes in the subtree, and COUNT is the number of | ||
| 3323 | nodes in the subtree, including NODE. */) | ||
| 3324 | (Lisp_Object node) | ||
| 3325 | { | ||
| 3326 | /* Having a limit on the depth to traverse doesn't have much impact | ||
| 3327 | on the time it takes, so I left that out. */ | ||
| 3328 | CHECK_TS_NODE (node); | ||
| 3329 | |||
| 3330 | treesit_initialize (); | ||
| 3331 | |||
| 3332 | TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (node)->node); | ||
| 3333 | ptrdiff_t max_depth = 1; | ||
| 3334 | ptrdiff_t max_width = 0; | ||
| 3335 | ptrdiff_t count = 0; | ||
| 3336 | ptrdiff_t current_depth = 0; | ||
| 3337 | |||
| 3338 | /* Traverse the subtree depth-first. */ | ||
| 3339 | while (true) | ||
| 3340 | { | ||
| 3341 | count++; | ||
| 3342 | |||
| 3343 | /* Go down depth-first. */ | ||
| 3344 | while (ts_tree_cursor_goto_first_child (&cursor)) | ||
| 3345 | { | ||
| 3346 | current_depth++; | ||
| 3347 | count++; | ||
| 3348 | /* While we're at here, measure the number of siblings. */ | ||
| 3349 | ptrdiff_t width_count = 1; | ||
| 3350 | while (ts_tree_cursor_goto_next_sibling (&cursor)) | ||
| 3351 | width_count++; | ||
| 3352 | max_width = max (max_width, width_count); | ||
| 3353 | /* Go back to the first sibling. */ | ||
| 3354 | treesit_assume_true (ts_tree_cursor_goto_parent (&cursor)); | ||
| 3355 | treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor)); | ||
| 3356 | } | ||
| 3357 | max_depth = max (max_depth, current_depth); | ||
| 3358 | |||
| 3359 | /* Go to next sibling. If there is no next sibling, go to | ||
| 3360 | parent's next sibling, and so on. If there is no more | ||
| 3361 | parent, we've traversed the whole subtree, stop. */ | ||
| 3362 | while (!ts_tree_cursor_goto_next_sibling (&cursor)) | ||
| 3363 | { | ||
| 3364 | if (ts_tree_cursor_goto_parent (&cursor)) | ||
| 3365 | current_depth--; | ||
| 3366 | else | ||
| 3367 | { | ||
| 3368 | ts_tree_cursor_delete (&cursor); | ||
| 3369 | return list3 (make_fixnum (max_depth), | ||
| 3370 | make_fixnum (max_width), | ||
| 3371 | make_fixnum (count)); | ||
| 3372 | } | ||
| 3373 | } | ||
| 3374 | } | ||
| 3375 | } | ||
| 3376 | |||
| 3315 | #endif /* HAVE_TREE_SITTER */ | 3377 | #endif /* HAVE_TREE_SITTER */ |
| 3316 | 3378 | ||
| 3317 | DEFUN ("treesit-available-p", Ftreesit_available_p, | 3379 | DEFUN ("treesit-available-p", Ftreesit_available_p, |
| @@ -3511,6 +3573,7 @@ then in the system default locations for dynamic libraries, in that order. */); | |||
| 3511 | defsubr (&Streesit_search_subtree); | 3573 | defsubr (&Streesit_search_subtree); |
| 3512 | defsubr (&Streesit_search_forward); | 3574 | defsubr (&Streesit_search_forward); |
| 3513 | defsubr (&Streesit_induce_sparse_tree); | 3575 | defsubr (&Streesit_induce_sparse_tree); |
| 3576 | defsubr (&Streesit_subtree_stat); | ||
| 3514 | #endif /* HAVE_TREE_SITTER */ | 3577 | #endif /* HAVE_TREE_SITTER */ |
| 3515 | defsubr (&Streesit_available_p); | 3578 | defsubr (&Streesit_available_p); |
| 3516 | } | 3579 | } |
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() { | |||
| 114 | { | 114 | { |
| 115 | puts ("Hello"); | 115 | puts ("Hello"); |
| 116 | } | 116 | } |
| 117 | for (int i=0; i<5; i++) | 117 | for (int i=0; |
| 118 | i<5; | ||
| 119 | i++) | ||
| 118 | if (true) | 120 | if (true) |
| 119 | { | 121 | { |
| 120 | puts ("Hello"); | 122 | puts ("Hello"); |
| @@ -141,7 +143,9 @@ int main() { | |||
| 141 | if (true) { | 143 | if (true) { |
| 142 | puts ("Hello"); | 144 | puts ("Hello"); |
| 143 | } | 145 | } |
| 144 | for (int i=0; i<5; i++) | 146 | for (int i=0; |
| 147 | i<5; | ||
| 148 | i++) | ||
| 145 | if (true) { | 149 | if (true) { |
| 146 | puts ("Hello"); | 150 | puts ("Hello"); |
| 147 | } | 151 | } |