Function: treesit-range-rules
treesit-range-rules is a byte-compiled function defined in
treesit.el.gz.
Signature
(treesit-range-rules &rest QUERY-SPECS)
Documentation
Produce settings for treesit-range-settings.
QUERY-SPECS are a series of QUERY-SPECs, where each QUERY-SPEC is a QUERY preceded by zero or more pairs of :KEYWORD and VALUE, like this:
:KEYWORD VALUE... QUERY
Each QUERY is a tree-sitter query in either the string, s-expression or compiled form.
Capture names generally don't matter, but names that start with an
underscore are ignored. The @language capture name is reserved.
For each QUERY, :KEYWORD and VALUE pairs add meta information to it. For example,
(treesit-range-rules
:embed 'javascript
:host 'html
:offset '(1 . -1)
'((script_element (raw_text) @javascript)))
The :embed keyword specifies the embedded language, and the
:host keyword specifies the host language. They are used in
this way: Emacs queries QUERY in the host language's parser,
computes the ranges spanned by the captured nodes, and applies
these ranges to parsers for the embedded language.
If the embedded language is dynamic, then :embed can specify a function.
This function will be passed a node as an argument, and should return
the language symbol for the embedded code block. The node is the one
captured from QUERY with capture name @language. Make sure the code
block and language capture are in the same match group. The function
can return nil if no valid language can be found; in that case, the range
is discarded.
If there's a :local keyword with value t, the range computed by this QUERY is given a dedicated local parser. Otherwise, the range shares the same parser with other ranges.
If there's an :offset keyword with a pair of numbers, each captured range is offset by those numbers. For example, an offset of (1 . -1) will update a captured range of (2 . 8) to be (3 . 7). This can be used to exclude things like surrounding delimiters from being included in the range covered by an embedded parser.
If there's a :range-fn keyword with a function, Emacs uses that
function to compute the ranges to use for the embedded parser. The
function is passed the captured node and the offset given by the
:offset keyword, and should return a list of ranges, where each range
is a cons of the start and end position.
QUERY can also be a function that takes two arguments, START and END. If QUERY is a function, it doesn't need the :KEYWORD VALUE pair preceding it. This function should set the ranges for parsers in the current buffer in the region between START and END. It is OK for this function to set ranges in a larger region that encompasses the region between START and END.
Source Code
;; Defined in /usr/src/emacs/lisp/treesit.el.gz
(defun treesit-range-rules (&rest query-specs)
"Produce settings for `treesit-range-settings'.
QUERY-SPECS are a series of QUERY-SPECs, where each QUERY-SPEC is
a QUERY preceded by zero or more pairs of :KEYWORD and VALUE,
like this:
:KEYWORD VALUE... QUERY
Each QUERY is a tree-sitter query in either the string,
s-expression or compiled form.
Capture names generally don't matter, but names that start with an
underscore are ignored. The `@language' capture name is reserved.
For each QUERY, :KEYWORD and VALUE pairs add meta information to
it. For example,
(treesit-range-rules
:embed \\='javascript
:host \\='html
:offset \\='(1 . -1)
\\='((script_element (raw_text) @javascript)))
The `:embed' keyword specifies the embedded language, and the
`:host' keyword specifies the host language. They are used in
this way: Emacs queries QUERY in the host language's parser,
computes the ranges spanned by the captured nodes, and applies
these ranges to parsers for the embedded language.
If the embedded language is dynamic, then `:embed' can specify a function.
This function will be passed a node as an argument, and should return
the language symbol for the embedded code block. The node is the one
captured from QUERY with capture name `@language'. Make sure the code
block and language capture are in the same match group. The function
can return nil if no valid language can be found; in that case, the range
is discarded.
If there's a `:local' keyword with value t, the range computed by
this QUERY is given a dedicated local parser. Otherwise, the
range shares the same parser with other ranges.
If there's an `:offset' keyword with a pair of numbers, each
captured range is offset by those numbers. For example, an
offset of (1 . -1) will update a captured range of (2 . 8) to
be (3 . 7). This can be used to exclude things like surrounding
delimiters from being included in the range covered by an
embedded parser.
If there's a `:range-fn' keyword with a function, Emacs uses that
function to compute the ranges to use for the embedded parser. The
function is passed the captured node and the offset given by the
`:offset' keyword, and should return a list of ranges, where each range
is a cons of the start and end position.
QUERY can also be a function that takes two arguments, START and
END. If QUERY is a function, it doesn't need the :KEYWORD VALUE
pair preceding it. This function should set the ranges for
parsers in the current buffer in the region between START and
END. It is OK for this function to set ranges in a larger region
that encompasses the region between START and END."
(let (host embed offset result local range-fn)
(while query-specs
(pcase (pop query-specs)
(:local (when (eq t (pop query-specs))
(setq local t)))
(:host (let ((host-lang (pop query-specs)))
(unless (symbolp host-lang)
(signal 'treesit-error (list "Value of :host option should be a symbol" host-lang)))
(setq host host-lang)))
(:embed (let ((embed-lang (pop query-specs)))
(unless (or (symbolp embed-lang) (functionp embed-lang))
(signal 'treesit-error (list "Value of :embed option should be a symbol or a function" embed-lang)))
(setq embed embed-lang)))
(:offset (let ((range-offset (pop query-specs)))
(unless (and (consp range-offset)
(numberp (car range-offset))
(numberp (cdr range-offset)))
(signal 'treesit-error (list "Value of :offset option should be a pair of numbers" range-offset)))
(setq offset range-offset)))
(:range-fn (let ((range-fn (pop query-specs)))
(unless (functionp range-fn)
(signal 'treesit-error (list "Value of :range-fn option should be a function" range-fn)))
(setq range-fn range-fn)))
(query (if (functionp query)
(push (list query nil nil) result)
(when (null embed)
(signal 'treesit-error (list "Value of :embed option cannot be omitted")))
(when (null host)
(signal 'treesit-error (list "Value of :host option cannot be omitted")))
(when (treesit-available-p)
;; Don't replace this with
;; `treesit--compile-query-with-cache'.
;; `treesit-query-compile' is lazy and don't actually
;; load the grammar until the query is
;; used. `treesit--compile-query-with-cache' compiles
;; eagerly so it's not safe to use for this function
;; which might be called when loading a package. To
;; do it properly like font-lock, we need to not
;; compile the queries here, and compile them with
;; `treesit--compile-query-with-cache' when major
;; mode is enabled. Let's just keep things simple
;; and keep range rules as-is. Because for range
;; rules, the queries generally don't need to
;; computed dynamically, and queries are simple and
;; few, so recompiling isn't as much of a problem.
(push (list (treesit-query-compile host query)
embed local offset range-fn)
result)))
(setq host nil embed nil offset nil local nil range-fn nil))))
(nreverse result)))