mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-18 03:40:47 -08:00
Add :override flag for tree-sitter font-lock
* doc/lispref/modes.texi (Parser-based Font Lock): Update manual. * lisp/treesit.el (treesit-font-lock-settings): Update docstring. (treesit-font-lock-rules): Handle :override. (treesit-font-lock-fontify-region): Handle :override. Also set inhibit-point-motion-hooks to t.
This commit is contained in:
parent
7a4380b905
commit
23bb724c92
2 changed files with 77 additions and 20 deletions
|
|
@ -3911,6 +3911,7 @@ a value that @var{treesit-font-lock-settings} accepts. An example:
|
||||||
@group
|
@group
|
||||||
(treesit-font-lock-rules
|
(treesit-font-lock-rules
|
||||||
:language 'javascript
|
:language 'javascript
|
||||||
|
:override t
|
||||||
'((true) @@font-lock-constant-face
|
'((true) @@font-lock-constant-face
|
||||||
(false) @@font-lock-constant-face)
|
(false) @@font-lock-constant-face)
|
||||||
:language 'html
|
:language 'html
|
||||||
|
|
@ -3919,9 +3920,19 @@ a value that @var{treesit-font-lock-settings} accepts. An example:
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
This function takes a list of text or s-exp queries. Before each
|
This function takes a list of text or s-exp queries. Before each
|
||||||
query, there are @var{:keyword} and @var{value} pairs that configures
|
query, there are @var{:keyword} and @var{value} pairs that configure
|
||||||
that query. The @code{:lang} keyword sets the query’s language, and is
|
that query. The @code{:lang} keyword sets the query’s language and
|
||||||
currently the only recognized keyword.
|
every query must specify the language. Other keywords are optional:
|
||||||
|
|
||||||
|
@multitable @columnfractions .15 .15 .6
|
||||||
|
@headitem Keyword @tab Value @tab Description
|
||||||
|
@item @code{:override} @tab nil
|
||||||
|
@tab If the region already has a face, discard the new face
|
||||||
|
@item @tab t @tab Always apply the new face
|
||||||
|
@item @tab @code{append} @tab Append the new face to existing ones
|
||||||
|
@item @tab @code{prepend} @tab Prepend the new face to existing ones
|
||||||
|
@item @tab @code{keep} @tab Fill-in regions without an existing face
|
||||||
|
@end multitable
|
||||||
|
|
||||||
Capture names in @var{query} should be face names like
|
Capture names in @var{query} should be face names like
|
||||||
@code{font-lock-keyword-face}. The captured node will be fontified
|
@code{font-lock-keyword-face}. The captured node will be fontified
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,10 @@ in-order. START and END are passed to each range function."
|
||||||
|
|
||||||
;;; Font-lock
|
;;; Font-lock
|
||||||
|
|
||||||
|
(define-error 'treesit-font-lock-error
|
||||||
|
"Generic tree-sitter font-lock error"
|
||||||
|
'treesit-error)
|
||||||
|
|
||||||
(defvar-local treesit-font-lock-settings nil
|
(defvar-local treesit-font-lock-settings nil
|
||||||
"A list of SETTINGs for treesit-based fontification.
|
"A list of SETTINGs for treesit-based fontification.
|
||||||
|
|
||||||
|
|
@ -285,7 +289,7 @@ should always use `treesit-font-lock-rules' to set this variable.
|
||||||
|
|
||||||
Each SETTING is of form
|
Each SETTING is of form
|
||||||
|
|
||||||
(LANGUAGE QUERY)
|
(LANGUAGE QUERY OVERRIDE)
|
||||||
|
|
||||||
Each SETTING controls one parser (often of different language).
|
Each SETTING controls one parser (often of different language).
|
||||||
LANGUAGE is the language symbol. See Info node `(elisp)Language
|
LANGUAGE is the language symbol. See Info node `(elisp)Language
|
||||||
|
|
@ -296,7 +300,11 @@ query. See Info node `(elisp)Pattern Matching' for how to write
|
||||||
a query in either string or s-expression form. When using
|
a query in either string or s-expression form. When using
|
||||||
repeatedly, a compiled query is much faster than a string or sexp
|
repeatedly, a compiled query is much faster than a string or sexp
|
||||||
one, so it is recommend to compile your queries if it will be
|
one, so it is recommend to compile your queries if it will be
|
||||||
used over and over.")
|
used over and over.
|
||||||
|
|
||||||
|
OVERRIDE is the override flag for this query. Its value can be
|
||||||
|
t, nil, append, prepend, keep. See more in
|
||||||
|
`treesit-font-lock-rules'.")
|
||||||
|
|
||||||
(defun treesit-font-lock-rules (&rest args)
|
(defun treesit-font-lock-rules (&rest args)
|
||||||
"Return a value suitable for `treesit-font-lock-settings'.
|
"Return a value suitable for `treesit-font-lock-settings'.
|
||||||
|
|
@ -311,13 +319,22 @@ configure the query (and only that query). For example,
|
||||||
|
|
||||||
(treesit-font-lock-rules
|
(treesit-font-lock-rules
|
||||||
:language \\='javascript
|
:language \\='javascript
|
||||||
|
:override t
|
||||||
\\='((true) @font-lock-constant-face
|
\\='((true) @font-lock-constant-face
|
||||||
(false) @font-lock-constant-face)
|
(false) @font-lock-constant-face)
|
||||||
:language \\='html
|
:language \\='html
|
||||||
\"(script_element) @font-lock-builtin-face\")
|
\"(script_element) @font-lock-builtin-face\")
|
||||||
|
|
||||||
For each QUERY, a :language keyword is required. Currently the
|
For each QUERY, a :language keyword is required. Other keywords
|
||||||
only recognized keyword is :language.
|
include:
|
||||||
|
|
||||||
|
KEYWORD VALUE DESCRIPTION
|
||||||
|
:override nil If the region already has a face,
|
||||||
|
discard the new face
|
||||||
|
t Always apply the new face
|
||||||
|
append Append the new face to existing ones
|
||||||
|
prepend Prepend the new face to existing ones
|
||||||
|
keep Fill-in regions without an existing face
|
||||||
|
|
||||||
Capture names in QUERY should be face names like
|
Capture names in QUERY should be face names like
|
||||||
`font-lock-keyword-face'. The captured node will be fontified
|
`font-lock-keyword-face'. The captured node will be fontified
|
||||||
|
|
@ -333,6 +350,8 @@ ignored.
|
||||||
(let (;; Tracks the current language that following queries will
|
(let (;; Tracks the current language that following queries will
|
||||||
;; apply to.
|
;; apply to.
|
||||||
(current-language nil)
|
(current-language nil)
|
||||||
|
;; Tracks :override flag.
|
||||||
|
(current-override nil)
|
||||||
;; The list this function returns.
|
;; The list this function returns.
|
||||||
(result nil))
|
(result nil))
|
||||||
(while args
|
(while args
|
||||||
|
|
@ -343,29 +362,40 @@ ignored.
|
||||||
(when (or (not (symbolp lang)) (null lang))
|
(when (or (not (symbolp lang)) (null lang))
|
||||||
(signal 'wrong-type-argument `(symbolp ,lang)))
|
(signal 'wrong-type-argument `(symbolp ,lang)))
|
||||||
(setq current-language lang)))
|
(setq current-language lang)))
|
||||||
|
(:override
|
||||||
|
(let ((flag (pop args)))
|
||||||
|
(when (not (memq flag '(t nil append prepend keep)))
|
||||||
|
(signal 'wrong-type-argument
|
||||||
|
`((or t nil append prepend keep)
|
||||||
|
,flag)))
|
||||||
|
(setq current-override flag)))
|
||||||
((pred treesit-query-p)
|
((pred treesit-query-p)
|
||||||
(when (null current-language)
|
(when (null current-language)
|
||||||
(signal 'treesit-error
|
(signal 'treesit-font-lock-error
|
||||||
`("Language unspecified, use :language keyword to specify a language for this query" ,token)))
|
`("Language unspecified, use :language keyword to specify a language for this query" ,token)))
|
||||||
(if (treesit-compiled-query-p token)
|
(if (treesit-compiled-query-p token)
|
||||||
(push `(,current-language token) result)
|
(push `(,current-language token) result)
|
||||||
(push `(,current-language
|
(push `(,current-language
|
||||||
,(treesit-query-compile current-language token))
|
,(treesit-query-compile current-language token)
|
||||||
|
,current-override)
|
||||||
result))
|
result))
|
||||||
;; Clears any configurations set for this query.
|
;; Clears any configurations set for this query.
|
||||||
(setq current-language nil))
|
(setq current-language nil
|
||||||
(_ (signal 'treesit-error
|
current-override nil))
|
||||||
|
(_ (signal 'treesit-font-lock-error
|
||||||
`("Unexpected value" token))))))
|
`("Unexpected value" token))))))
|
||||||
(nreverse result)))
|
(nreverse result)))
|
||||||
|
|
||||||
(defun treesit-font-lock-fontify-region (start end &optional loudly)
|
(defun treesit-font-lock-fontify-region
|
||||||
|
(start end &optional loudly)
|
||||||
"Fontify the region between START and END.
|
"Fontify the region between START and END.
|
||||||
If LOUDLY is non-nil, message some debugging information."
|
If LOUDLY is non-nil, message some debugging information."
|
||||||
(treesit-update-ranges start end)
|
(treesit-update-ranges start end)
|
||||||
(font-lock-unfontify-region start end)
|
(font-lock-unfontify-region start end)
|
||||||
(dolist (setting treesit-font-lock-settings)
|
(dolist (setting treesit-font-lock-settings)
|
||||||
(when-let* ((language (nth 0 setting))
|
(let* ((language (nth 0 setting))
|
||||||
(match-pattern (nth 1 setting))
|
(match-pattern (nth 1 setting))
|
||||||
|
(override (nth 2 setting))
|
||||||
(parser (treesit-parser-create language)))
|
(parser (treesit-parser-create language)))
|
||||||
(when-let ((node (treesit-node-on start end parser)))
|
(when-let ((node (treesit-node-on start end parser)))
|
||||||
(let ((captures (treesit-query-capture
|
(let ((captures (treesit-query-capture
|
||||||
|
|
@ -374,15 +404,31 @@ If LOUDLY is non-nil, message some debugging information."
|
||||||
;; often than not, NODE will be the root
|
;; often than not, NODE will be the root
|
||||||
;; node, and if we don't specify the range,
|
;; node, and if we don't specify the range,
|
||||||
;; we are basically querying the whole file.
|
;; we are basically querying the whole file.
|
||||||
start end)))
|
start end))
|
||||||
|
(inhibit-point-motion-hooks t))
|
||||||
(with-silent-modifications
|
(with-silent-modifications
|
||||||
(dolist (capture captures)
|
(dolist (capture captures)
|
||||||
(let* ((face (car capture))
|
(let* ((face (car capture))
|
||||||
(node (cdr capture))
|
(node (cdr capture))
|
||||||
(start (treesit-node-start node))
|
(start (treesit-node-start node))
|
||||||
(end (treesit-node-end node)))
|
(end (treesit-node-end node)))
|
||||||
(cond ((facep face)
|
(cond
|
||||||
(put-text-property start end 'face face))
|
((facep face)
|
||||||
|
(pcase override
|
||||||
|
('nil (unless (text-property-not-all
|
||||||
|
start end 'face nil)
|
||||||
|
(put-text-property start end 'face face)))
|
||||||
|
('t (put-text-property start end 'face face))
|
||||||
|
('append (font-lock-append-text-property
|
||||||
|
start end 'face face))
|
||||||
|
('prepend (font-lock-prepend-text-property
|
||||||
|
start end 'face face))
|
||||||
|
('keep (font-lock-fillin-text-property
|
||||||
|
start end 'face face))
|
||||||
|
(_ (signal 'treesit-font-lock-error
|
||||||
|
(list
|
||||||
|
"Unrecognized value of :override option"
|
||||||
|
override)))))
|
||||||
((functionp face)
|
((functionp face)
|
||||||
(funcall face start end node)))
|
(funcall face start end node)))
|
||||||
;; Don't raise an error if FACE is neither a face nor
|
;; Don't raise an error if FACE is neither a face nor
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue