Add treesit-query-with-fallback

* lisp/treesit.el (treesit-font-lock-rules): Handle
treesit-query-with-fallback.
(treesit-query-with-fallback): New function.
* doc/lispref/modes.texi (Parser-based Font Lock): Mention
treesit-query-with-fallback.
This commit is contained in:
Yuan Fu 2026-04-27 01:16:10 -07:00
parent d19c511425
commit 241481cf1e
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
3 changed files with 41 additions and 5 deletions

View file

@ -4447,6 +4447,14 @@ arguments as optional arguments for future extensibility.
If a capture name is both a face and a function, the face takes
priority. If a capture name is neither a face nor a function, it is
ignored.
@findex treesit-query-with-optional
@findex treesit-query-with-fallback
Sometimes, to support different versions of the same grammar, it's
useful to conditionally include some optional @var{query}, or choose the
first valid query from a list of queries. Functions like
@code{treesit-query-with-optional} and
@code{treesit-query-with-fallback} can come in handy.
@end defun
@c FIXME: Cross-ref treesit-font-lock-level to user manual.

View file

@ -1295,6 +1295,17 @@ information.
Multi-language major modes can rely on the default return value from
'treesit-language-at' that uses the new function 'treesit-parsers-at'.
+++
*** New function 'treesit-query-with-optional'.
When used in 'treesit-font-lock-rules', 'treesit-query-with-optional'
returns a default query plus the valid queries from a list of optional
queries.
+++
*** New function 'treesit-query-with-fallback'.
When used in 'treesit-font-lock-rules', 'treesit-query-with-fallback'
selects the first valid query from a list.
+++
*** Tree-sitter thing functions now work better with multiple parsers.
The following functions now handle better the case when there are

View file

@ -1660,7 +1660,12 @@ name, it is ignored."
;; The list this function returns.
(result nil))
(while query-specs
(let ((token (pop query-specs)))
(let ((token (pop query-specs))
(reset (lambda ()
(setq current-language nil
current-override nil
current-feature nil
current-reversed nil))))
(pcase token
;; (1) Process keywords.
(:default-language
@ -1719,10 +1724,10 @@ name, it is ignored."
lang)
result)
;; Clears any configurations set for this query.
(setq current-language nil
current-override nil
current-feature nil
current-reversed nil)))
(funcall reset)))
;; (3) Skip this query, for whatever reason. Currently only
;; utilized by `treesit-query-with-fallback' and undocumented.
('nil (funcall reset))
(_ (signal 'treesit-font-lock-error
`("Unexpected value" ,token))))))
(nreverse result))))
@ -1743,6 +1748,18 @@ Use LANGUAGE for validating queries."
(push query optional))))
(append mandatory optional)))
(defun treesit-query-with-fallback (language &rest queries)
"Return the first valid query in QUERIES.
Return nil if no query is valid. Use LANGUAGE for validating queries."
(declare (indent 1))
(catch 'return
(dolist (query queries)
(ignore-errors
(when (treesit--compile-query-with-cache language query)
(throw 'return query))))
nil))
;; `font-lock-fontify-region-function' has the LOUDLY argument, but
;; `jit-lock-functions' doesn't pass that argument. So even if we set
;; `font-lock-verbose' to t, if jit-lock is enabled (and it's almost