mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-30 08:09:04 +00:00
Merge from origin/emacs-29
8360e12f0e
Update to Org 9.6.1-23-gc45a059058601308
; * doc/emacs/misc.texi (Document View): Remove @footnote...197f994384
Document tree-sitter features in the user manualb73539832d
; Remove treesit--font-lock-fast-mode-grace-count64fee21d5f
Fix dockerfile-ts-mode line continuation indentation (bug...1970726e26
Use treesit-subtree-stat to determine treesit--font-lock-...382e018856
Add treesit-subtree-stata3003492ac
Move c-ts-mode--statement-offset to c-ts-common.el4b1714571c
; Fix byte-compile warnings in c-ts-mode.elf50cb7d7c4
; Improve docstring of c-ts-mode--indent-style-setter1c3ca3bb64
Fix <> syntax in rust-ts-mode56e8607dc9
Fix spurious errors on Windows when deleting temporary *....2bd0b94753
Fix java class member without access modifier (bug#61115)1de6ebf287
Make treesit-font-lock-level a defcustom6e50ee8bbb
Add c-ts-mode-set-style and :set for c-ts-mode-indent-style450db0587a
Minor documentation improvements for outline-minor-mode (...578e892671
; * doc/lispref/variables.texi (File Local Variables): Im...bc5ee2b7bf
; * src/comp.c: Remove Local Variables section to avoid w...362678d90e
python.el: Use correct regexp when enabling python-ts-mode76bb46db9d
; * doc/emacs/frames.texi (Mouse References): Improve ind... # Conflicts: # doc/emacs/programs.texi # etc/NEWS # lisp/progmodes/c-ts-mode.el
This commit is contained in:
commit
207a0d9408
@ -1024,17 +1024,65 @@ customize-group @key{RET} font-lock-faces @key{RET}}. You can then
|
||||
use that customization buffer to customize the appearance of these
|
||||
faces. @xref{Face Customization}.
|
||||
|
||||
@cindex just-in-time (JIT) font-lock
|
||||
@cindex background syntax highlighting
|
||||
Fontifying very large buffers can take a long time. To avoid large
|
||||
delays when a file is visited, Emacs initially fontifies only the
|
||||
visible portion of a buffer. As you scroll through the buffer, each
|
||||
portion that becomes visible is fontified as soon as it is displayed;
|
||||
this type of Font Lock is called @dfn{Just-In-Time} (or @dfn{JIT})
|
||||
Lock. You can control how JIT Lock behaves, including telling it to
|
||||
perform fontification while idle, by customizing variables in the
|
||||
customization group @samp{jit-lock}. @xref{Specific Customization}.
|
||||
|
||||
The information that major modes use for determining which parts of
|
||||
buffer text to fontify and what faces to use can be based on several
|
||||
different ways of analyzing the text:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Search for keywords and other textual patterns based on regular
|
||||
expressions (@pxref{Regexp Search,, Regular Expression Search}).
|
||||
|
||||
@item
|
||||
Find syntactically distinct parts of text based on built-in syntax
|
||||
tables (@pxref{Syntax Tables,,, elisp, The Emacs Lisp Reference
|
||||
Manual}).
|
||||
|
||||
@item
|
||||
Use syntax tree produced by a full-blown parser, via a special-purpose
|
||||
library, such as the tree-sitter library (@pxref{Parsing Program
|
||||
Source,,, elisp, The Emacs Lisp Reference Manual}), or an external
|
||||
program.
|
||||
@end itemize
|
||||
|
||||
@menu
|
||||
* Traditional Font Lock:: Font Lock based on regexps and syntax tables.
|
||||
* Parser-based Font Lock:: Font Lock based on external parser.
|
||||
@end menu
|
||||
|
||||
@node Traditional Font Lock
|
||||
@subsection Traditional Font Lock
|
||||
@cindex traditional font-lock
|
||||
|
||||
``Traditional'' methods of providing font-lock information are based
|
||||
on regular-expression search and on syntactic analysis using syntax
|
||||
tables built into Emacs. This subsection describes the use and
|
||||
customization of font-lock for major modes which use these traditional
|
||||
methods.
|
||||
|
||||
@vindex font-lock-maximum-decoration
|
||||
You can customize the variable @code{font-lock-maximum-decoration}
|
||||
to alter the amount of fontification applied by Font Lock mode, for
|
||||
major modes that support this feature. The value should be a number
|
||||
(with 1 representing a minimal amount of fontification; some modes
|
||||
support levels as high as 3); or @code{t}, meaning ``as high as
|
||||
possible'' (the default). To be effective for a given file buffer,
|
||||
the customization of @code{font-lock-maximum-decoration} should be
|
||||
done @emph{before} the file is visited; if you already have the file
|
||||
visited in a buffer when you customize this variable, kill the buffer
|
||||
and visit the file again after the customization.
|
||||
You can control the amount of fontification applied by Font Lock
|
||||
mode by customizing the variable @code{font-lock-maximum-decoration},
|
||||
for major modes that support this feature. The value of this variable
|
||||
should be a number (with 1 representing a minimal amount of
|
||||
fontification; some modes support levels as high as 3); or @code{t},
|
||||
meaning ``as high as possible'' (the default). To be effective for a
|
||||
given file buffer, the customization of
|
||||
@code{font-lock-maximum-decoration} should be done @emph{before} the
|
||||
file is visited; if you already have the file visited in a buffer when
|
||||
you customize this variable, kill the buffer and visit the file again
|
||||
after the customization.
|
||||
|
||||
You can also specify different numbers for particular major modes; for
|
||||
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,
|
||||
@pxref{Customizing Keywords,,, elisp, The Emacs Lisp Reference
|
||||
Manual}.
|
||||
|
||||
@cindex just-in-time (JIT) font-lock
|
||||
@cindex background syntax highlighting
|
||||
Fontifying large buffers can take a long time. To avoid large
|
||||
delays when a file is visited, Emacs initially fontifies only the
|
||||
visible portion of a buffer. As you scroll through the buffer, each
|
||||
portion that becomes visible is fontified as soon as it is displayed;
|
||||
this type of Font Lock is called @dfn{Just-In-Time} (or @dfn{JIT})
|
||||
Lock. You can control how JIT Lock behaves, including telling it to
|
||||
perform fontification while idle, by customizing variables in the
|
||||
customization group @samp{jit-lock}. @xref{Specific Customization}.
|
||||
@node Parser-based Font Lock
|
||||
@subsection Parser-based Font Lock
|
||||
@cindex font-lock via tree-sitter
|
||||
@cindex parser-based font-lock
|
||||
If your Emacs was built with the tree-sitter library, it can use the
|
||||
results of parsing the buffer text by that library for the purposes of
|
||||
fontification. This is usually faster and more accurate than the
|
||||
``traditional'' methods described in the previous subsection, since
|
||||
the tree-sitter library provides full-blown parsers for programming
|
||||
languages and other kinds of formatted text which it supports. Major
|
||||
modes which utilize the tree-sitter library are named
|
||||
@code{@var{foo}-ts-mode}, with the @samp{-ts-} part indicating the use
|
||||
of the library. This subsection documents the Font Lock support based
|
||||
on the tree-sitter library.
|
||||
|
||||
@vindex treesit-font-lock-level
|
||||
You can control the amount of fontification applied by Font Lock
|
||||
mode of major modes based on tree-sitter by customizing the variable
|
||||
@code{treesit-font-lock-level}. Its value is a number between 1 and
|
||||
4:
|
||||
|
||||
@table @asis
|
||||
@item Level 1
|
||||
This level usually fontifies only comments and function names in
|
||||
function definitions.
|
||||
@item Level 2
|
||||
This level adds fontification of keywords, strings, and data types.
|
||||
@item Level 3
|
||||
This is the default level; it adds fontification of assignments,
|
||||
numbers, properties, etc.
|
||||
@item Level 4
|
||||
This level adds everything else that can be fontified: operators,
|
||||
delimiters, brackets, other punctuation, function names in function
|
||||
calls, variables, etc.
|
||||
@end table
|
||||
|
||||
@vindex treesit-font-lock-feature-list
|
||||
@noindent
|
||||
What exactly constitutes each of the syntactical categories mentioned
|
||||
above depends on the major mode and the parser grammar used by
|
||||
tree-sitter for the major-mode's language. However, in general the
|
||||
categories follow the conventions of the programming language or the
|
||||
file format supported by the major mode. The buffer-local value of
|
||||
the variable @code{treesit-font-lock-feature-list} holds the
|
||||
fontification features supported by a tree-sitter based major mode,
|
||||
where each sub-list shows the features provided by the corresponding
|
||||
fontification level.
|
||||
|
||||
Once you change the value of @code{treesit-font-lock-level} via
|
||||
@w{@kbd{M-x customize-variable}} (@pxref{Specific Customization}), it
|
||||
takes effect immediately in all the existing buffers and for files you
|
||||
visit in the future in the same session.
|
||||
|
||||
|
||||
@node Highlight Interactively
|
||||
@section Interactive Highlighting
|
||||
|
@ -383,6 +383,10 @@ Controlling the Display
|
||||
* Visual Line Mode:: Word wrap and screen line-based editing.
|
||||
* Display Custom:: Information on variables for customizing display.
|
||||
|
||||
Font Lock
|
||||
* Traditional Font Lock:: Font Lock based on regexps and syntax tables.
|
||||
* Parser-based Font Lock:: Font Lock based on external parser.
|
||||
|
||||
Searching and Replacement
|
||||
|
||||
* Incremental Search:: Search happens as you type the string.
|
||||
|
@ -215,6 +215,17 @@ by the integers that Emacs can represent (@pxref{Buffers}). If you
|
||||
try, Emacs displays an error message saying that the maximum buffer
|
||||
size has been exceeded.
|
||||
|
||||
@vindex treesit-max-buffer-size
|
||||
If you try to visit a file whose major mode (@pxref{Major Modes})
|
||||
uses the tree-sitter parsing library, Emacs will display a warning if
|
||||
the file's size in bytes is larger than the value of the variable
|
||||
@code{treesit-max-buffer-size}. The default value is 40 megabytes for
|
||||
64-bit Emacs and 15 megabytes for 32-bit Emacs. This avoids the
|
||||
danger of having Emacs run out of memory by preventing the activation
|
||||
of major modes based on tree-sitter in such large buffers, because a
|
||||
typical tree-sitter parser needs about 10 times as much memory as the
|
||||
text it parses.
|
||||
|
||||
@cindex wildcard characters in file names
|
||||
@vindex find-file-wildcards
|
||||
If the file name you specify contains shell-style wildcard
|
||||
|
@ -334,6 +334,7 @@ In this way, you can use the mouse to move point over a button without
|
||||
activating it. Dragging the mouse over or onto a button has its usual
|
||||
behavior of setting the region, and does not activate the button.
|
||||
|
||||
@vindex mouse-1-click-follows-link
|
||||
You can change how @kbd{mouse-1} applies to buttons by customizing
|
||||
the variable @code{mouse-1-click-follows-link}. If the value is a
|
||||
positive integer, that determines how long you need to hold the mouse
|
||||
|
@ -470,11 +470,7 @@ documents. It provides features such as slicing, zooming, and
|
||||
searching inside documents. It works by converting the document to a
|
||||
set of images using the @command{gs} (GhostScript) or
|
||||
@command{pdfdraw}/@command{mutool draw} (MuPDF) commands and other
|
||||
external tools @footnote{PostScript files require GhostScript, DVI
|
||||
files require @code{dvipdf} or @code{dvipdfm}, OpenDocument and
|
||||
Microsoft Office documents require the @code{unoconv} tool, and EPUB,
|
||||
CBZ, FB2, XPS and OXPS files require @code{mutool} to be available.},
|
||||
and displaying those images.
|
||||
external tools, and then displays those converted images.
|
||||
|
||||
@findex doc-view-toggle-display
|
||||
@findex doc-view-minor-mode
|
||||
|
@ -255,6 +255,17 @@ they do their standard jobs in a way better fitting a particular
|
||||
language. Other major modes may replace any or all of these key
|
||||
bindings for that purpose.
|
||||
|
||||
@cindex nested defuns
|
||||
@vindex treesit-defun-tactic
|
||||
Some programming languages supported @dfn{nested defuns}, whereby a
|
||||
defun (such as a function or a method or a class) can be defined
|
||||
inside (i.e., as part of the body) of another defun. The commands
|
||||
described above by default find the beginning and the end of the
|
||||
@emph{innermost} defun around point. Major modes based on the
|
||||
tree-sitter library provide control of this behavior: if the variable
|
||||
@code{treesit-defun-tactic} is set to the value @code{top-level}, the
|
||||
defun commands will find the @emph{outermost} defuns instead.
|
||||
|
||||
@node Moving by Sentences
|
||||
@subsection Moving by Sentences
|
||||
@cindex sentences, in programming languages
|
||||
@ -599,15 +610,19 @@ then indent it like this:
|
||||
@item C-c C-q
|
||||
@kindex C-c C-q @r{(C mode)}
|
||||
@findex c-indent-defun
|
||||
@findex c-ts-mode-indent-defun
|
||||
Reindent the current top-level function definition or aggregate type
|
||||
declaration (@code{c-indent-defun}).
|
||||
declaration (@code{c-indent-defun} in CC mode,
|
||||
@code{c-ts-mode-indent-defun} in @code{c-ts-mode} based on tree-sitter).
|
||||
|
||||
@item C-M-q
|
||||
@kindex C-M-q @r{(C mode)}
|
||||
@findex c-indent-exp
|
||||
Reindent each line in the balanced expression that follows point
|
||||
(@code{c-indent-exp}). A prefix argument inhibits warning messages
|
||||
about invalid syntax.
|
||||
@findex prog-indent-sexp
|
||||
Reindent each line in the balanced expression that follows point. In
|
||||
CC mode, this invokes @code{c-indent-exp}; in tree-sitter based
|
||||
@code{c-ts-mode} this invokes a more general @code{prog-indent-sexp}.
|
||||
A prefix argument inhibits warning messages about invalid syntax.
|
||||
|
||||
@item @key{TAB}
|
||||
@findex c-indent-line-or-region
|
||||
@ -647,7 +662,8 @@ onto the indentation of the @dfn{anchor statement}.
|
||||
|
||||
@table @kbd
|
||||
@item C-c . @var{style} @key{RET}
|
||||
Select a predefined style @var{style} (@code{c-set-style}).
|
||||
Select a predefined style @var{style} (@code{c-set-style} in CC mode,
|
||||
@code{c-ts-mode-set-style} in @code{c-ts-mode} based on tree-sitter).
|
||||
@end table
|
||||
|
||||
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.
|
||||
|
||||
@kindex C-c . @r{(C mode)}
|
||||
@findex c-set-style
|
||||
@findex c-ts-mode-set-style
|
||||
To choose a style for the current buffer, use the command @w{@kbd{C-c
|
||||
.}}. Specify a style name as an argument (case is not significant).
|
||||
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
|
||||
new style, you can type @kbd{C-x h C-M-\}.
|
||||
|
||||
@vindex c-default-style
|
||||
You can also set the variable @code{c-default-style} to specify the
|
||||
default style for various major modes. Its value should be either the
|
||||
style's name (a string) or an alist, in which each element specifies
|
||||
one major mode and which indentation style to use for it. For
|
||||
example,
|
||||
When using CC mode, you can also set the variable
|
||||
@code{c-default-style} to specify the default style for various major
|
||||
modes. Its value should be either the style's name (a string) or an
|
||||
alist, in which each element specifies one major mode and which
|
||||
indentation style to use for it. For example,
|
||||
|
||||
@example
|
||||
(setq c-default-style
|
||||
@ -692,6 +709,11 @@ one of the C-like major modes; thus, if you specify a new default
|
||||
style for Java mode, you can make it take effect in an existing Java
|
||||
mode buffer by typing @kbd{M-x java-mode} there.
|
||||
|
||||
@vindex c-ts-mode-indent-style
|
||||
When using the tree-sitter based @code{c-ts-mode}, you can set the
|
||||
default indentation style by customizing the variable
|
||||
@code{c-ts-mode-indent-style}.
|
||||
|
||||
The @code{gnu} style specifies the formatting recommended by the GNU
|
||||
Project for C; it is the default, so as to encourage use of our
|
||||
recommended style.
|
||||
|
@ -1021,14 +1021,16 @@ this variable is @code{insert}, the buttons are inserted directly into
|
||||
the buffer text, so @key{RET} on the button will also toggle display
|
||||
of the section, like a mouse click does. If the value is
|
||||
@code{in-margins}, Outline minor mode will use the window margins to
|
||||
indicate that a section is hidden.
|
||||
indicate that a section is hidden. The buttons are customizable as icons
|
||||
(@pxref{Icons}).
|
||||
|
||||
@vindex outline-minor-mode-cycle
|
||||
If the @code{outline-minor-mode-cycle} user option is
|
||||
non-@code{nil}, the @kbd{TAB} and @kbd{S-@key{TAB}} keys are enabled on the
|
||||
outline heading lines. @kbd{TAB} cycles hiding, showing the
|
||||
sub-heading, and showing all for the current section. @kbd{S-@key{TAB}}
|
||||
does the same for the entire buffer.
|
||||
non-@code{nil}, the @kbd{TAB} and @kbd{S-@key{TAB}} keys that cycle
|
||||
the visibility are enabled on the outline heading lines
|
||||
(@pxref{Outline Visibility, outline-cycle}). @kbd{TAB} cycles hiding,
|
||||
showing the sub-heading, and showing all for the current section.
|
||||
@kbd{S-@key{TAB}} does the same for the entire buffer.
|
||||
|
||||
@node Outline Format
|
||||
@subsection Format of Outlines
|
||||
|
@ -2023,6 +2023,7 @@ file-local variables stored in @code{file-local-variables-alist}.
|
||||
@end defvar
|
||||
|
||||
@cindex safe local variable
|
||||
@cindex @code{safe-local-variable}, property of variable
|
||||
You can specify safe values for a variable with a
|
||||
@code{safe-local-variable} property. The property has to be a
|
||||
function of one argument; any value is safe if the function returns
|
||||
|
@ -1018,6 +1018,8 @@ quotes removed.
|
||||
|
||||
---
|
||||
*** 'M-x apropos-variable' output now includes values of variables.
|
||||
Such apropos buffer is more easily viewed with outlining after
|
||||
enabling 'outline-minor-mode' in 'apropos-mode'.
|
||||
|
||||
+++
|
||||
*** New docstring syntax to indicate that symbols shouldn't be links.
|
||||
@ -2480,6 +2482,10 @@ matches.
|
||||
---
|
||||
*** New function 'xref-show-xrefs'.
|
||||
|
||||
*** 'outline-minor-mode' is supported in Xref buffers.
|
||||
You can enable outlining by adding 'outline-minor-mode' to
|
||||
'xref-after-update-hook'.
|
||||
|
||||
** File Notifications
|
||||
|
||||
+++
|
||||
|
@ -4112,13 +4112,16 @@ the deferred compilation mechanism."
|
||||
(native-elisp-load data)))
|
||||
;; We may have created a temporary file when we're being
|
||||
;; called with something other than a file as the argument.
|
||||
;; Delete it.
|
||||
;; Delete it if we can.
|
||||
(when (and (not (stringp function-or-file))
|
||||
(not output)
|
||||
comp-ctxt
|
||||
(comp-ctxt-output comp-ctxt)
|
||||
(file-exists-p (comp-ctxt-output comp-ctxt)))
|
||||
(delete-file (comp-ctxt-output comp-ctxt))))))))
|
||||
(cond ((eq 'windows-nt system-type)
|
||||
;; We may still be using the temporary .eln file.
|
||||
(ignore-errors (delete-file (comp-ctxt-output comp-ctxt))))
|
||||
(t (delete-file (comp-ctxt-output comp-ctxt))))))))))
|
||||
|
||||
(defun native-compile-async-skip-p (file load selector)
|
||||
"Return non-nil if FILE's compilation should be skipped.
|
||||
|
@ -3474,13 +3474,17 @@ This ensures the export commands can easily use it."
|
||||
(when (setq tmp (plist-get props 'date))
|
||||
(when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
|
||||
(let ((calendar-date-display-form
|
||||
'(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left))))
|
||||
'((format "%s-%.2d-%.2d" year
|
||||
(string-to-number month)
|
||||
(string-to-number day)))))
|
||||
(setq tmp (calendar-date-string tmp)))
|
||||
(setq props (plist-put props 'date tmp)))
|
||||
(when (setq tmp (plist-get props 'day))
|
||||
(when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
|
||||
(let ((calendar-date-display-form
|
||||
'(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left))))
|
||||
'((format "%s-%.2d-%.2d" year
|
||||
(string-to-number month)
|
||||
(string-to-number day)))))
|
||||
(setq tmp (calendar-date-string tmp)))
|
||||
(setq props (plist-put props 'day tmp))
|
||||
(setq props (plist-put props 'agenda-day tmp)))
|
||||
|
@ -46,7 +46,7 @@
|
||||
;; `org-git-version' check because the generated Org version strings
|
||||
;; will not match.
|
||||
`(unless (equal (org-release) ,(org-release))
|
||||
(warn "Org version mismatch. Make sure that correct `load-path' is set early in init.el
|
||||
(warn "Org version mismatch. Org loading aborted.
|
||||
This warning usually appears when a built-in Org version is loaded
|
||||
prior to the more recent Org version.
|
||||
|
||||
|
@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made."
|
||||
(defun org-git-version ()
|
||||
"The Git version of Org mode.
|
||||
Inserted by installing Org or when a release is made."
|
||||
(let ((org-git-version "release_9.6.1-16-ge37e9b"))
|
||||
(let ((org-git-version "release_9.6.1-23-gc45a05"))
|
||||
org-git-version))
|
||||
|
||||
(provide 'org-version)
|
||||
|
@ -8608,6 +8608,7 @@ or to another Org file, automatically push the old position onto the ring."
|
||||
(defvar org-agenda-buffer-name)
|
||||
(defun org-follow-timestamp-link ()
|
||||
"Open an agenda view for the time-stamp date/range at point."
|
||||
(require 'org-agenda)
|
||||
;; Avoid changing the global value.
|
||||
(let ((org-agenda-buffer-name org-agenda-buffer-name))
|
||||
(cond
|
||||
|
@ -6600,14 +6600,14 @@ see.
|
||||
Optional argument POST-PROCESS is a function which should accept
|
||||
no argument. It is always called within the current process,
|
||||
from BUFFER, with point at its beginning. Export back-ends can
|
||||
use it to set a major mode there, e.g,
|
||||
use it to set a major mode there, e.g.,
|
||||
|
||||
(defun org-latex-export-as-latex
|
||||
(&optional async subtreep visible-only body-only ext-plist)
|
||||
(interactive)
|
||||
(org-export-to-buffer \\='latex \"*Org LATEX Export*\"
|
||||
async subtreep visible-only body-only ext-plist
|
||||
#'LaTeX-mode))
|
||||
#\\='LaTeX-mode))
|
||||
|
||||
When expressed as an anonymous function, using `lambda',
|
||||
POST-PROCESS needs to be quoted.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
;; Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
;; Author : 付禹安 (Yuan Fu) <casouri@gmail.com>
|
||||
;; Maintainer : 付禹安 (Yuan Fu) <casouri@gmail.com>
|
||||
;; Keywords : c c++ java javascript rust languages tree-sitter
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
@ -22,7 +22,10 @@
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; For C-like language major modes:
|
||||
;; This file contains functions that can be shared by C-like language
|
||||
;; major modes, like indenting and filling "/* */" block comments.
|
||||
;;
|
||||
;; For indenting and filling comments:
|
||||
;;
|
||||
;; - Use `c-ts-common-comment-setup' to setup comment variables and
|
||||
;; filling.
|
||||
@ -30,6 +33,14 @@
|
||||
;; - Use simple-indent matcher `c-ts-common-looking-at-star' and
|
||||
;; anchor `c-ts-common-comment-start-after-first-star' for indenting
|
||||
;; block comments. See `c-ts-mode--indent-styles' for example.
|
||||
;;
|
||||
;; For indenting statements:
|
||||
;;
|
||||
;; - Set `c-ts-common-indent-offset',
|
||||
;; `c-ts-common-indent-block-type-regexp', and
|
||||
;; `c-ts-common-indent-bracketless-type-regexp', then use simple-indent
|
||||
;; offset `c-ts-common-statement-offset' in
|
||||
;; `treesit-simple-indent-rules'.
|
||||
|
||||
;;; Code:
|
||||
|
||||
@ -40,6 +51,8 @@
|
||||
(declare-function treesit-node-end "treesit.c")
|
||||
(declare-function treesit-node-type "treesit.c")
|
||||
|
||||
;;; Comment indentation and filling
|
||||
|
||||
(defun c-ts-common-looking-at-star (_n _p bol &rest _)
|
||||
"A tree-sitter simple indent matcher.
|
||||
Matches if there is a \"*\" after BOL."
|
||||
@ -242,6 +255,107 @@ Set up:
|
||||
(setq-local paragraph-separate paragraph-start)
|
||||
(setq-local fill-paragraph-function #'c-ts-common--fill-paragraph))
|
||||
|
||||
;;; Statement indent
|
||||
|
||||
(defvar c-ts-common-indent-offset nil
|
||||
"Indent offset used by `c-ts-common' indent functions.
|
||||
|
||||
This should be the symbol of the indent offset variable for the
|
||||
particular major mode. This cannot be nil for `c-ts-common'
|
||||
statement indent functions to work.")
|
||||
|
||||
(defvar c-ts-common-indent-block-type-regexp nil
|
||||
"Regexp matching types of block nodes (i.e., {} blocks).
|
||||
|
||||
This cannot be nil for `c-ts-common' statement indent functions
|
||||
to work.")
|
||||
|
||||
(defvar c-ts-common-indent-bracketless-type-regexp nil
|
||||
"A regexp matching types of bracketless constructs.
|
||||
|
||||
These constructs include if, while, do-while, for statements. In
|
||||
these statements, the body can omit the bracket, which requires
|
||||
special handling from our bracket-counting indent algorithm.
|
||||
|
||||
This can be nil, meaning such special handling is not needed.")
|
||||
|
||||
(defun c-ts-common-statement-offset (node parent &rest _)
|
||||
"This anchor is used for children of a statement inside a block.
|
||||
|
||||
This function basically counts the number of block nodes (i.e.,
|
||||
brackets) (defined by `c-ts-mode--indent-block-type-regexp')
|
||||
between NODE and the root node (not counting NODE itself), and
|
||||
multiply that by `c-ts-common-indent-offset'.
|
||||
|
||||
To support GNU style, on each block level, this function also
|
||||
checks whether the opening bracket { is on its own line, if so,
|
||||
it adds an extra level, except for the top-level.
|
||||
|
||||
PARENT is NODE's parent."
|
||||
(let ((level 0))
|
||||
;; If point is on an empty line, NODE would be nil, but we pretend
|
||||
;; there is a statement node.
|
||||
(when (null node)
|
||||
(setq node t))
|
||||
;; If NODE is a opening bracket on its own line, take off one
|
||||
;; level because the code below assumes NODE is a statement
|
||||
;; _inside_ a {} block.
|
||||
(when (string-match-p c-ts-common-indent-block-type-regexp
|
||||
(treesit-node-type node))
|
||||
(cl-decf level))
|
||||
;; Go up the tree and compute indent level.
|
||||
(while (if (eq node t)
|
||||
(setq node parent)
|
||||
node)
|
||||
(when (string-match-p c-ts-common-indent-block-type-regexp
|
||||
(treesit-node-type node))
|
||||
(cl-incf level)
|
||||
(save-excursion
|
||||
(goto-char (treesit-node-start node))
|
||||
;; Add an extra level if the opening bracket is on its own
|
||||
;; line, except (1) it's at top-level, or (2) it's immediate
|
||||
;; parent is another block.
|
||||
(cond ((bolp) nil) ; Case (1).
|
||||
((let ((parent-type (treesit-node-type
|
||||
(treesit-node-parent node))))
|
||||
;; Case (2).
|
||||
(and parent-type
|
||||
(or (string-match-p
|
||||
c-ts-common-indent-block-type-regexp
|
||||
parent-type))))
|
||||
nil)
|
||||
;; Add a level.
|
||||
((looking-back (rx bol (* whitespace))
|
||||
(line-beginning-position))
|
||||
(cl-incf level)))))
|
||||
(setq level (c-ts-mode--fix-bracketless-indent level node))
|
||||
;; Go up the tree.
|
||||
(setq node (treesit-node-parent node)))
|
||||
(* level (symbol-value c-ts-common-indent-offset))))
|
||||
|
||||
(defun c-ts-mode--fix-bracketless-indent (level node)
|
||||
"Takes LEVEL and NODE and return adjusted LEVEL.
|
||||
This fixes indentation for cases shown in bug#61026. Basically
|
||||
in C-like syntax, statements like if, for, while sometimes omit
|
||||
the bracket in the body."
|
||||
(let ((block-re c-ts-common-indent-block-type-regexp)
|
||||
(statement-re
|
||||
c-ts-common-indent-bracketless-type-regexp)
|
||||
(node-type (treesit-node-type node))
|
||||
(parent-type (treesit-node-type (treesit-node-parent node))))
|
||||
(if (and block-re statement-re node-type parent-type
|
||||
(not (string-match-p block-re node-type))
|
||||
(string-match-p statement-re parent-type))
|
||||
(1+ level)
|
||||
level)))
|
||||
|
||||
(defun c-ts-mode--close-bracket-offset (node parent &rest _)
|
||||
"Offset for the closing bracket, NODE.
|
||||
It's basically one level less that the statements in the block.
|
||||
PARENT is NODE's parent."
|
||||
(- (c-ts-common-statement-offset node parent)
|
||||
(symbol-value c-ts-common-indent-offset)))
|
||||
|
||||
(provide 'c-ts-common)
|
||||
|
||||
;;; c-ts-common.el ends here
|
||||
|
@ -63,11 +63,6 @@
|
||||
;; will set up Emacs to use the C/C++ modes defined here for other
|
||||
;; files, provided that you have the corresponding parser grammar
|
||||
;; libraries installed.
|
||||
;;
|
||||
;; - Use variable `c-ts-mode-indent-block-type-regexp' with indent
|
||||
;; offset c-ts-mode--statement-offset for indenting statements.
|
||||
;; Again, see `c-ts-mode--indent-styles' for example.
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
@ -92,6 +87,28 @@
|
||||
:safe 'integerp
|
||||
:group 'c)
|
||||
|
||||
(defun c-ts-mode--indent-style-setter (sym val)
|
||||
"Custom setter for `c-ts-mode-set-style'.
|
||||
Apart from setting the default value of SYM to VAL, also change
|
||||
the value of SYM in `c-ts-mode' and `c++-ts-mode' buffers to VAL."
|
||||
(set-default sym val)
|
||||
(named-let loop ((res nil)
|
||||
(buffers (buffer-list)))
|
||||
(if (null buffers)
|
||||
(mapc (lambda (b)
|
||||
(with-current-buffer b
|
||||
(setq-local treesit-simple-indent-rules
|
||||
(treesit--indent-rules-optimize
|
||||
(c-ts-mode--get-indent-style
|
||||
(if (eq major-mode 'c-ts-mode) 'c 'cpp))))))
|
||||
res)
|
||||
(let ((buffer (car buffers)))
|
||||
(with-current-buffer buffer
|
||||
;; FIXME: Should we use `derived-mode-p' here?
|
||||
(if (or (eq major-mode 'c-ts-mode) (eq major-mode 'c++-ts-mode))
|
||||
(loop (append res (list buffer)) (cdr buffers))
|
||||
(loop res (cdr buffers))))))))
|
||||
|
||||
(defcustom c-ts-mode-indent-style 'gnu
|
||||
"Style used for indentation.
|
||||
|
||||
@ -100,13 +117,42 @@ one of the supplied styles doesn't suffice a function could be
|
||||
set instead. This function is expected return a list that
|
||||
follows the form of `treesit-simple-indent-rules'."
|
||||
:version "29.1"
|
||||
:type '(choice (symbol :tag "Gnu" 'gnu)
|
||||
(symbol :tag "K&R" 'k&r)
|
||||
(symbol :tag "Linux" 'linux)
|
||||
(symbol :tag "BSD" 'bsd)
|
||||
:type '(choice (symbol :tag "Gnu" gnu)
|
||||
(symbol :tag "K&R" k&r)
|
||||
(symbol :tag "Linux" linux)
|
||||
(symbol :tag "BSD" bsd)
|
||||
(function :tag "A function for user customized style" ignore))
|
||||
:set #'c-ts-mode--indent-style-setter
|
||||
:group 'c)
|
||||
|
||||
(defun c-ts-mode--get-indent-style (mode)
|
||||
"Helper function to set indentation style.
|
||||
MODE is either `c' or `cpp'."
|
||||
(let ((style
|
||||
(if (functionp c-ts-mode-indent-style)
|
||||
(funcall c-ts-mode-indent-style)
|
||||
(alist-get c-ts-mode-indent-style (c-ts-mode--indent-styles mode)))))
|
||||
`((,mode ,@style))))
|
||||
|
||||
(defun c-ts-mode-set-style ()
|
||||
"Set the indent style of C/C++ modes globally.
|
||||
|
||||
This changes the current indent style of every C/C++ buffer and
|
||||
the default C/C++ indent style in this Emacs session."
|
||||
(interactive)
|
||||
;; FIXME: Should we use `derived-mode-p' here?
|
||||
(or (eq major-mode 'c-ts-mode) (eq major-mode 'c++-ts-mode)
|
||||
(error "Buffer %s is not a c-ts-mode (c-ts-mode-set-style)"
|
||||
(buffer-name)))
|
||||
(c-ts-mode--indent-style-setter
|
||||
'c-ts-mode-indent-style
|
||||
;; NOTE: We can probably use the interactive form for this.
|
||||
(intern
|
||||
(completing-read
|
||||
"Select style: "
|
||||
(mapcar #'car (c-ts-mode--indent-styles (if (eq major-mode 'c-ts-mode) 'c 'cpp)))
|
||||
nil t nil nil "gnu"))))
|
||||
|
||||
;;; Syntax table
|
||||
|
||||
(defvar c-ts-mode--syntax-table
|
||||
@ -177,7 +223,7 @@ MODE is either `c' or `cpp'."
|
||||
;; Labels.
|
||||
((node-is "labeled_statement") parent-bol 0)
|
||||
((parent-is "labeled_statement")
|
||||
point-min c-ts-mode--statement-offset)
|
||||
point-min c-ts-common-statement-offset)
|
||||
|
||||
((match "preproc_ifdef" "compound_statement") point-min 0)
|
||||
((match "#endif" "preproc_ifdef") point-min 0)
|
||||
@ -186,15 +232,6 @@ MODE is either `c' or `cpp'."
|
||||
((match "preproc_function_def" "compound_statement") point-min 0)
|
||||
((match "preproc_call" "compound_statement") point-min 0)
|
||||
|
||||
;; {} blocks.
|
||||
((node-is "}") point-min c-ts-mode--close-bracket-offset)
|
||||
((parent-is "compound_statement")
|
||||
point-min c-ts-mode--statement-offset)
|
||||
((parent-is "enumerator_list")
|
||||
point-min c-ts-mode--statement-offset)
|
||||
((parent-is "field_declaration_list")
|
||||
point-min c-ts-mode--statement-offset)
|
||||
|
||||
((parent-is "function_definition") parent-bol 0)
|
||||
((parent-is "conditional_expression") first-sibling 0)
|
||||
((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset)
|
||||
@ -215,13 +252,16 @@ MODE is either `c' or `cpp'."
|
||||
;; Indent the body of namespace definitions.
|
||||
((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset)))
|
||||
|
||||
;; int[5] a = { 0, 0, 0, 0 };
|
||||
((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "if_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "for_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "while_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "switch_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "case_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "do_statement") parent-bol c-ts-mode-indent-offset)
|
||||
((parent-is "enumerator_list") point-min c-ts-common-statement-offset)
|
||||
((parent-is "field_declaration_list") point-min c-ts-common-statement-offset)
|
||||
|
||||
;; {} blocks.
|
||||
((node-is "}") point-min c-ts-mode--close-bracket-offset)
|
||||
((parent-is "compound_statement") point-min c-ts-common-statement-offset)
|
||||
((node-is "compound_statement") point-min c-ts-common-statement-offset)
|
||||
|
||||
,@(when (eq mode 'cpp)
|
||||
`(((node-is "field_initializer_list") parent-bol ,(* c-ts-mode-indent-offset 2)))))))
|
||||
`((gnu
|
||||
@ -249,19 +289,6 @@ MODE is either `c' or `cpp'."
|
||||
((parent-is "do_statement") parent-bol 0)
|
||||
,@common))))
|
||||
|
||||
(defun c-ts-mode--set-indent-style (mode)
|
||||
"Helper function to set indentation style.
|
||||
MODE is either `c' or `cpp'."
|
||||
(let ((style
|
||||
(if (functionp c-ts-mode-indent-style)
|
||||
(funcall c-ts-mode-indent-style)
|
||||
(pcase c-ts-mode-indent-style
|
||||
('gnu (alist-get 'gnu (c-ts-mode--indent-styles mode)))
|
||||
('k&r (alist-get 'k&r (c-ts-mode--indent-styles mode)))
|
||||
('bsd (alist-get 'bsd (c-ts-mode--indent-styles mode)))
|
||||
('linux (alist-get 'linux (c-ts-mode--indent-styles mode)))))))
|
||||
`((,mode ,@style))))
|
||||
|
||||
(defun c-ts-mode--top-level-label-matcher (node &rest _)
|
||||
"A matcher that matches a top-level label.
|
||||
NODE should be a labeled_statement."
|
||||
@ -273,90 +300,6 @@ NODE should be a labeled_statement."
|
||||
"labeled_statement")
|
||||
(not (treesit-node-top-level func "compound_statement")))))
|
||||
|
||||
(defvar c-ts-mode-indent-block-type-regexp
|
||||
(rx (or "compound_statement"
|
||||
"field_declaration_list"
|
||||
"enumerator_list"))
|
||||
"Regexp matching types of block nodes (i.e., {} blocks).")
|
||||
|
||||
(defvar c-ts-mode--statement-offset-post-processr nil
|
||||
"A functions that makes adjustments to `c-ts-mode--statement-offset'.
|
||||
|
||||
This is a function that takes two arguments, the current indent
|
||||
level and the current node, and returns a new level.
|
||||
|
||||
When `c-ts-mode--statement-offset' runs and go up the parse tree,
|
||||
it increments the indent level when some condition are met in
|
||||
each level. At each level, after (possibly) incrementing the
|
||||
offset, it calls this function, passing it the current indent
|
||||
level and the current node, and use the return value as the new
|
||||
indent level.")
|
||||
|
||||
(defun c-ts-mode--statement-offset (node parent &rest _)
|
||||
"This anchor is used for children of a statement inside a block.
|
||||
|
||||
This function basically counts the number of block nodes (defined
|
||||
by `c-ts-mode--indent-block-type-regexp') between NODE and the
|
||||
root node (not counting NODE itself), and multiply that by
|
||||
`c-ts-mode-indent-offset'.
|
||||
|
||||
To support GNU style, on each block level, this function also
|
||||
checks whether the opening bracket { is on its own line, if so,
|
||||
it adds an extra level, except for the top-level.
|
||||
|
||||
PARENT is NODE's parent."
|
||||
(let ((level 0))
|
||||
;; If point is on an empty line, NODE would be nil, but we pretend
|
||||
;; there is a statement node.
|
||||
(when (null node)
|
||||
(setq node t))
|
||||
(while (if (eq node t)
|
||||
(setq node parent)
|
||||
(setq node (treesit-node-parent node)))
|
||||
(when (string-match-p c-ts-mode-indent-block-type-regexp
|
||||
(treesit-node-type node))
|
||||
(cl-incf level)
|
||||
(save-excursion
|
||||
(goto-char (treesit-node-start node))
|
||||
;; Add an extra level if the opening bracket is on its own
|
||||
;; line, except (1) it's at top-level, or (2) it's immediate
|
||||
;; parent is another block.
|
||||
(cond ((bolp) nil) ; Case (1).
|
||||
((let ((parent-type (treesit-node-type
|
||||
(treesit-node-parent node))))
|
||||
;; Case (2).
|
||||
(and parent-type
|
||||
(string-match-p c-ts-mode-indent-block-type-regexp
|
||||
parent-type)))
|
||||
nil)
|
||||
;; Add a level.
|
||||
((looking-back (rx bol (* whitespace))
|
||||
(line-beginning-position))
|
||||
(cl-incf level)))))
|
||||
(when c-ts-mode--statement-offset-post-processr
|
||||
(setq level (funcall c-ts-mode--statement-offset-post-processr
|
||||
level node))))
|
||||
(* level c-ts-mode-indent-offset)))
|
||||
|
||||
(defun c-ts-mode--fix-bracketless-indent (level node)
|
||||
"Takes LEVEL and NODE and returns adjusted LEVEL.
|
||||
This fixes indentation for cases shown in bug#61026. Basically
|
||||
in C/C++, constructs like if, for, while sometimes don't have
|
||||
bracket."
|
||||
(if (and (not (equal (treesit-node-type node) "compound_statement"))
|
||||
(member (treesit-node-type (treesit-node-parent node))
|
||||
'("if_statement" "while_statement" "do_statement"
|
||||
"for_statement")))
|
||||
(1+ level)
|
||||
level))
|
||||
|
||||
(defun c-ts-mode--close-bracket-offset (node parent &rest _)
|
||||
"Offset for the closing bracket, NODE.
|
||||
It's basically one level less that the statements in the block.
|
||||
PARENT is NODE's parent."
|
||||
(- (c-ts-mode--statement-offset node parent)
|
||||
c-ts-mode-indent-offset))
|
||||
|
||||
;;; Font-lock
|
||||
|
||||
(defvar c-ts-mode--preproc-keywords
|
||||
@ -757,7 +700,8 @@ the semicolon. This function skips the semicolon."
|
||||
(defvar-keymap c-ts-mode-map
|
||||
:doc "Keymap for the C language with tree-sitter"
|
||||
:parent prog-mode-map
|
||||
"C-c C-q" #'c-ts-mode-indent-defun)
|
||||
"C-c C-q" #'c-ts-mode-indent-defun
|
||||
"C-c ." #'c-ts-mode-set-style)
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode c-ts-base-mode prog-mode "C"
|
||||
@ -817,8 +761,14 @@ the semicolon. This function skips the semicolon."
|
||||
;; Indent.
|
||||
(when (eq c-ts-mode-indent-style 'linux)
|
||||
(setq-local indent-tabs-mode t))
|
||||
(setq-local c-ts-mode--statement-offset-post-processr
|
||||
#'c-ts-mode--fix-bracketless-indent)
|
||||
(setq-local c-ts-common-indent-offset 'c-ts-mode-indent-offset)
|
||||
(setq-local c-ts-common-indent-block-type-regexp
|
||||
(rx (or "compound_statement"
|
||||
"field_declaration_list"
|
||||
"enumerator_list")))
|
||||
(setq-local c-ts-common-indent-bracketless-type-regexp
|
||||
(rx (or "if_statement" "do_statement"
|
||||
"for_statement" "while_statement")))
|
||||
|
||||
;; Comment
|
||||
(c-ts-common-comment-setup)
|
||||
@ -871,7 +821,7 @@ in your configuration."
|
||||
(setq-local comment-end " */")
|
||||
;; Indent.
|
||||
(setq-local treesit-simple-indent-rules
|
||||
(c-ts-mode--set-indent-style 'c))
|
||||
(c-ts-mode--get-indent-style 'c))
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
|
||||
(treesit-major-mode-setup)))
|
||||
@ -907,7 +857,7 @@ in your configuration."
|
||||
|
||||
;; Indent.
|
||||
(setq-local treesit-simple-indent-rules
|
||||
(c-ts-mode--set-indent-style 'cpp))
|
||||
(c-ts-mode--get-indent-style 'cpp))
|
||||
|
||||
;; Font-lock.
|
||||
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
|
||||
|
@ -51,9 +51,27 @@
|
||||
((parent-is "expose_instruction") (nth-sibling 1) 0)
|
||||
((parent-is "label_instruction") (nth-sibling 1) 0)
|
||||
((parent-is "shell_command") first-sibling 0)
|
||||
((parent-is "string_array") first-sibling 1)))
|
||||
((parent-is "string_array") first-sibling 1)
|
||||
((dockerfile-ts-mode--line-continuation-p) dockerfile-ts-mode--line-continuation-anchor 0)))
|
||||
"Tree-sitter indent rules.")
|
||||
|
||||
(defun dockerfile-ts-mode--line-continuation-p ()
|
||||
"Return t if the current node is a line continuation node."
|
||||
(lambda (node _ _ &rest _)
|
||||
(string= (treesit-node-type node) "\n")))
|
||||
|
||||
(defun dockerfile-ts-mode--line-continuation-anchor (_ _ &rest _)
|
||||
"This anchor is used to align any nodes that are part of a line
|
||||
continuation to the previous entry."
|
||||
(save-excursion
|
||||
(forward-line -1)
|
||||
(let ((prev-node (treesit-node-at (point))))
|
||||
(if (string= (treesit-node-type prev-node) "\\\n")
|
||||
(back-to-indentation)
|
||||
(forward-word)
|
||||
(forward-char))
|
||||
(+ 1 (- (point) (pos-bol))))))
|
||||
|
||||
(defvar dockerfile-ts-mode--keywords
|
||||
'("ADD" "ARG" "AS" "CMD" "COPY" "CROSS_BUILD" "ENTRYPOINT" "ENV"
|
||||
"EXPOSE" "FROM" "HEALTHCHECK" "LABEL" "MAINTAINER" "ONBUILD" "RUN"
|
||||
|
@ -89,6 +89,7 @@
|
||||
((query "(method_declaration (block (_) @indent))") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "local_variable_declaration") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "expression_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((match "type_identifier" "field_declaration") parent-bol 0)
|
||||
((parent-is "field_declaration") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "return_statement") parent-bol java-ts-mode-indent-offset)
|
||||
((parent-is "variable_declarator") parent-bol java-ts-mode-indent-offset)
|
||||
|
@ -6715,8 +6715,8 @@ implementations: `python-mode' and `python-ts-mode'."
|
||||
(when python-indent-guess-indent-offset
|
||||
(python-indent-guess-indent-offset))
|
||||
|
||||
(add-to-list 'auto-mode-alist
|
||||
'("\\.py[iw]?\\'\\|python[0-9.]*" . python-ts-mode))))
|
||||
(add-to-list 'auto-mode-alist '("\\.py[iw]?\\'" . python-ts-mode))
|
||||
(add-to-list 'interpreter-mode-alist '("python[0-9.]*" . python-ts-mode))))
|
||||
|
||||
;;; Completion predicates for M-x
|
||||
;; Commands that only make sense when editing Python code
|
||||
|
@ -275,6 +275,28 @@ Return nil if there is no name or if NODE is not a defun node."
|
||||
(treesit-node-text
|
||||
(treesit-node-child-by-field-name node "name") t))))
|
||||
|
||||
(defun rust-ts-mode--syntax-propertize (beg end)
|
||||
"Apply syntax text property to template delimiters between BEG and END.
|
||||
|
||||
< and > are usually punctuation, e.g., as greater/less-than. But
|
||||
when used for types, they should be considered pairs.
|
||||
|
||||
This function checks for < and > in the changed RANGES and apply
|
||||
appropriate text property to alter the syntax of template
|
||||
delimiters < and >'s."
|
||||
(goto-char beg)
|
||||
(while (re-search-forward (rx (or "<" ">")) end t)
|
||||
(pcase (treesit-node-type
|
||||
(treesit-node-parent
|
||||
(treesit-node-at (match-beginning 0))))
|
||||
("type_arguments"
|
||||
(put-text-property (match-beginning 0)
|
||||
(match-end 0)
|
||||
'syntax-table
|
||||
(pcase (char-before)
|
||||
(?< '(4 . ?>))
|
||||
(?> '(5 . ?<))))))))
|
||||
|
||||
;;;###autoload
|
||||
(define-derived-mode rust-ts-mode prog-mode "Rust"
|
||||
"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."
|
||||
(when (treesit-ready-p 'rust)
|
||||
(treesit-parser-create 'rust)
|
||||
|
||||
;; Syntax.
|
||||
(setq-local syntax-propertize-function
|
||||
#'rust-ts-mode--syntax-propertize)
|
||||
|
||||
;; Comments.
|
||||
(c-ts-common-comment-setup)
|
||||
|
||||
|
107
lisp/treesit.el
107
lisp/treesit.el
@ -554,7 +554,25 @@ omitted, default END to BEG."
|
||||
"Generic tree-sitter font-lock error"
|
||||
'treesit-error)
|
||||
|
||||
(defvar-local treesit-font-lock-level 3
|
||||
(defun treesit--font-lock-level-setter (sym val)
|
||||
"Custom setter for `treesit-font-lock-level'."
|
||||
(set-default sym val)
|
||||
(named-let loop ((res nil)
|
||||
(buffers (buffer-list)))
|
||||
(if (null buffers)
|
||||
(mapc (lambda (b)
|
||||
(with-current-buffer b
|
||||
(setq-local treesit-font-lock-level val)
|
||||
(treesit-font-lock-recompute-features)
|
||||
(treesit-font-lock-fontify-region (point-min) (point-max))))
|
||||
res)
|
||||
(let ((buffer (car buffers)))
|
||||
(with-current-buffer buffer
|
||||
(if (treesit-parser-list)
|
||||
(loop (append res (list buffer)) (cdr buffers))
|
||||
(loop res (cdr buffers))))))))
|
||||
|
||||
(defcustom treesit-font-lock-level 3
|
||||
"Decoration level to be used by tree-sitter fontifications.
|
||||
|
||||
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
|
||||
fontifications.
|
||||
|
||||
Level 1 usually contains only comments and definitions.
|
||||
Level 2 usually adds keywords, strings, constants, types, etc.
|
||||
Level 3 usually represents a full-blown fontification, including
|
||||
assignment, constants, numbers, properties, etc.
|
||||
Level 2 usually adds keywords, strings, data types, etc.
|
||||
Level 3 usually represents full-blown fontifications, including
|
||||
assignments, constants, numbers and literals, properties, etc.
|
||||
Level 4 adds everything else that can be fontified: delimiters,
|
||||
operators, brackets, all functions and variables, etc.
|
||||
operators, brackets, punctuation, all functions and variables, etc.
|
||||
|
||||
In addition to the decoration level, individual features can be
|
||||
turned on/off by calling `treesit-font-lock-recompute-features'.
|
||||
Changing the decoration level requires calling
|
||||
`treesit-font-lock-recompute-features' to have an effect.")
|
||||
`treesit-font-lock-recompute-features' to have an effect, unless
|
||||
done via `customize-variable'.
|
||||
|
||||
To see which syntactical categories are fontified by each level
|
||||
in a particular major mode, examine the buffer-local value of the
|
||||
variable `treesit-font-lock-feature-list'."
|
||||
:type 'integer
|
||||
:set #'treesit--font-lock-level-setter
|
||||
:version "29.1")
|
||||
|
||||
(defvar-local treesit--font-lock-query-expand-range (cons 0 0)
|
||||
"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."
|
||||
(push r result))
|
||||
(push child result))
|
||||
(setq child (treesit-node-next-sibling child)))
|
||||
;; If NODE has no child, keep NODE.
|
||||
(or result (list node))))
|
||||
;; If NODE has no child, keep NODE. If LIMIT is exceeded, return
|
||||
;; nil.
|
||||
(or result (and (> limit 0) (list node)))))
|
||||
|
||||
(defsubst treesit--node-length (node)
|
||||
"Return the length of the text of NODE."
|
||||
(- (treesit-node-end node) (treesit-node-start node)))
|
||||
|
||||
(defvar-local treesit--font-lock-fast-mode nil
|
||||
(defvar-local treesit--font-lock-fast-mode 'unspecified
|
||||
"If this variable is t, change the way we query so it's faster.
|
||||
This is not a general optimization and should be RARELY needed!
|
||||
See comments in `treesit-font-lock-fontify-region' for more
|
||||
detail.")
|
||||
|
||||
(defvar-local treesit--font-lock-fast-mode-grace-count 5
|
||||
"Grace counts before we turn on the fast mode.
|
||||
|
||||
When query takes abnormally long time to execute, we turn on the
|
||||
\"fast mode\", but just to be on the safe side, we only turn on
|
||||
the fast mode after this number of offenses. See bug#60691,
|
||||
bug#60223.")
|
||||
|
||||
;; Some details worth explaining:
|
||||
;;
|
||||
;; 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."
|
||||
(enable (nth 1 setting))
|
||||
(override (nth 3 setting))
|
||||
(language (treesit-query-language query)))
|
||||
(when-let ((nodes (list (treesit-buffer-root-node language)))
|
||||
;; Only activate if ENABLE flag is t.
|
||||
(activate (eq t enable)))
|
||||
(ignore activate)
|
||||
|
||||
;; If we run into problematic files, use the "fast mode" to
|
||||
;; try to recover. See comment #2 above for more explanation.
|
||||
(when treesit--font-lock-fast-mode
|
||||
(setq nodes (treesit--children-covering-range-recurse
|
||||
(car nodes) start end (* 4 jit-lock-chunk-size))))
|
||||
;; Use deterministic way to decide whether to turn on "fast
|
||||
;; mode". (See bug#60691, bug#60223.)
|
||||
(when (eq treesit--font-lock-fast-mode 'unspecified)
|
||||
(pcase-let ((`(,max-depth ,max-width)
|
||||
(treesit-subtree-stat
|
||||
(treesit-buffer-root-node language))))
|
||||
(if (or (> max-depth 100) (> max-width 4000))
|
||||
(setq treesit--font-lock-fast-mode t)
|
||||
(setq treesit--font-lock-fast-mode nil))))
|
||||
|
||||
(when-let* ((root (treesit-buffer-root-node language))
|
||||
(nodes (if (eq t treesit--font-lock-fast-mode)
|
||||
(treesit--children-covering-range-recurse
|
||||
root start end (* 4 jit-lock-chunk-size))
|
||||
(list (treesit-buffer-root-node language))))
|
||||
;; Only activate if ENABLE flag is t.
|
||||
(activate (eq t enable)))
|
||||
(ignore activate)
|
||||
|
||||
;; Query each node.
|
||||
(dolist (sub-node nodes)
|
||||
(let* ((delta-start (car treesit--font-lock-query-expand-range))
|
||||
(delta-end (cdr treesit--font-lock-query-expand-range))
|
||||
(start-time (current-time))
|
||||
(captures (treesit-query-capture
|
||||
sub-node query
|
||||
(max (- start delta-start) (point-min))
|
||||
(min (+ end delta-end) (point-max))))
|
||||
(end-time (current-time)))
|
||||
;; If for any query the query time is strangely long,
|
||||
;; switch to fast mode (see comments above).
|
||||
(when (and (null treesit--font-lock-fast-mode)
|
||||
(> (time-to-seconds
|
||||
(time-subtract end-time start-time))
|
||||
0.01))
|
||||
(if (> treesit--font-lock-fast-mode-grace-count 0)
|
||||
(cl-decf treesit--font-lock-fast-mode-grace-count)
|
||||
(setq-local treesit--font-lock-fast-mode t)))
|
||||
(min (+ end delta-end) (point-max)))))
|
||||
|
||||
;; For each captured node, fontify that node.
|
||||
(with-silent-modifications
|
||||
@ -1002,12 +1019,14 @@ If LOUDLY is non-nil, display some debugging information."
|
||||
(node (cdr capture))
|
||||
(node-start (treesit-node-start node))
|
||||
(node-end (treesit-node-end node)))
|
||||
|
||||
;; If node is not in the region, take them out. See
|
||||
;; comment #3 above for more detail.
|
||||
(if (and (facep face)
|
||||
(or (>= start node-end) (>= node-start end)))
|
||||
(when (or loudly treesit--font-lock-verbose)
|
||||
(message "Captured node %s(%s-%s) but it is outside of fontifing region" node node-start node-end))
|
||||
|
||||
(cond
|
||||
((facep face)
|
||||
(treesit-fontify-with-override
|
||||
@ -1015,6 +1034,7 @@ If LOUDLY is non-nil, display some debugging information."
|
||||
face override))
|
||||
((functionp face)
|
||||
(funcall face node override start end)))
|
||||
|
||||
;; Don't raise an error if FACE is neither a face nor
|
||||
;; a function. This is to allow intermediate capture
|
||||
;; names used for #match and #eq.
|
||||
@ -3033,10 +3053,10 @@ function signals an error."
|
||||
:no-value (treesit-parser-set-included-ranges parser '((1 . 4) (5 . 8))))
|
||||
(treesit-parser-included-ranges
|
||||
:no-eval (treesit-parser-included-ranges parser)
|
||||
:eg-result '((1 . 4) (5 . 8)))
|
||||
:eg-result ((1 . 4) (5 . 8)))
|
||||
(treesit-query-range
|
||||
:no-eval (treesit-query-range node '((script_element) @cap))
|
||||
:eg-result-string '((1 . 4) (5 . 8)))
|
||||
:eg-result ((1 . 4) (5 . 8)))
|
||||
|
||||
|
||||
"Retrieving a node"
|
||||
@ -3182,7 +3202,12 @@ function signals an error."
|
||||
:eg-result-string "#<treesit-node (translation_unit) in 1-11>")
|
||||
(treesit-query-string
|
||||
:no-eval (treesit-query-string "int c = 0;" '((identifier) @id) 'c)
|
||||
:eg-result-string "((id . #<treesit-node (identifier) in 5-6>))"))
|
||||
:eg-result-string "((id . #<treesit-node (identifier) in 5-6>))")
|
||||
|
||||
"Misc"
|
||||
(treesit-subtree-stat
|
||||
:no-eval (treesit-subtree-stat node)
|
||||
:eg-result (6 33 487)))
|
||||
|
||||
(provide 'treesit)
|
||||
|
||||
|
@ -5912,6 +5912,3 @@ file -> CU. */);
|
||||
|
||||
defsubr (&Snative_comp_available_p);
|
||||
}
|
||||
/* Local Variables: */
|
||||
/* c-file-offsets: ((arglist-intro . +)) */
|
||||
/* End: */
|
||||
|
@ -3312,6 +3312,68 @@ a regexp. */)
|
||||
return parent;
|
||||
}
|
||||
|
||||
DEFUN ("treesit-subtree-stat",
|
||||
Ftreesit_subtree_stat,
|
||||
Streesit_subtree_stat, 1, 1, 0,
|
||||
doc: /* Return information about the subtree of NODE.
|
||||
|
||||
Return a list (MAX-DEPTH MAX-WIDTH COUNT), where MAX-DEPTH is the
|
||||
maximum depth of the subtree, MAX-WIDTH is the maximum number of
|
||||
direct children of nodes in the subtree, and COUNT is the number of
|
||||
nodes in the subtree, including NODE. */)
|
||||
(Lisp_Object node)
|
||||
{
|
||||
/* Having a limit on the depth to traverse doesn't have much impact
|
||||
on the time it takes, so I left that out. */
|
||||
CHECK_TS_NODE (node);
|
||||
|
||||
treesit_initialize ();
|
||||
|
||||
TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (node)->node);
|
||||
ptrdiff_t max_depth = 1;
|
||||
ptrdiff_t max_width = 0;
|
||||
ptrdiff_t count = 0;
|
||||
ptrdiff_t current_depth = 0;
|
||||
|
||||
/* Traverse the subtree depth-first. */
|
||||
while (true)
|
||||
{
|
||||
count++;
|
||||
|
||||
/* Go down depth-first. */
|
||||
while (ts_tree_cursor_goto_first_child (&cursor))
|
||||
{
|
||||
current_depth++;
|
||||
count++;
|
||||
/* While we're at here, measure the number of siblings. */
|
||||
ptrdiff_t width_count = 1;
|
||||
while (ts_tree_cursor_goto_next_sibling (&cursor))
|
||||
width_count++;
|
||||
max_width = max (max_width, width_count);
|
||||
/* Go back to the first sibling. */
|
||||
treesit_assume_true (ts_tree_cursor_goto_parent (&cursor));
|
||||
treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor));
|
||||
}
|
||||
max_depth = max (max_depth, current_depth);
|
||||
|
||||
/* Go to next sibling. If there is no next sibling, go to
|
||||
parent's next sibling, and so on. If there is no more
|
||||
parent, we've traversed the whole subtree, stop. */
|
||||
while (!ts_tree_cursor_goto_next_sibling (&cursor))
|
||||
{
|
||||
if (ts_tree_cursor_goto_parent (&cursor))
|
||||
current_depth--;
|
||||
else
|
||||
{
|
||||
ts_tree_cursor_delete (&cursor);
|
||||
return list3 (make_fixnum (max_depth),
|
||||
make_fixnum (max_width),
|
||||
make_fixnum (count));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_TREE_SITTER */
|
||||
|
||||
DEFUN ("treesit-available-p", Ftreesit_available_p,
|
||||
@ -3511,6 +3573,7 @@ then in the system default locations for dynamic libraries, in that order. */);
|
||||
defsubr (&Streesit_search_subtree);
|
||||
defsubr (&Streesit_search_forward);
|
||||
defsubr (&Streesit_induce_sparse_tree);
|
||||
defsubr (&Streesit_subtree_stat);
|
||||
#endif /* HAVE_TREE_SITTER */
|
||||
defsubr (&Streesit_available_p);
|
||||
}
|
||||
|
@ -114,7 +114,9 @@ int main() {
|
||||
{
|
||||
puts ("Hello");
|
||||
}
|
||||
for (int i=0; i<5; i++)
|
||||
for (int i=0;
|
||||
i<5;
|
||||
i++)
|
||||
if (true)
|
||||
{
|
||||
puts ("Hello");
|
||||
@ -141,7 +143,9 @@ int main() {
|
||||
if (true) {
|
||||
puts ("Hello");
|
||||
}
|
||||
for (int i=0; i<5; i++)
|
||||
for (int i=0;
|
||||
i<5;
|
||||
i++)
|
||||
if (true) {
|
||||
puts ("Hello");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user