1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-04-27 08:43:40 -07:00

Allow major modes to tweak tree-sitter fontification

treesit--font-lock-query-expand-range allows a major mode to fix
fontification problems temporarily before the parser can be fixed.

* lisp/treesit.el (treesit--font-lock-query-expand-range): New variable.
(treesit-font-lock-fontify-region): Use the new variable.
* lisp/textmodes/css-mode.el (css-ts-mode): Use the new variable.
This commit is contained in:
Yuan Fu 2022-11-21 11:26:46 -08:00
parent 0cbb7d3bd0
commit 6cf8bf5042
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
2 changed files with 34 additions and 9 deletions

View file

@ -1813,6 +1813,11 @@ can also be used to fill comments.
'((selector comment)
(property constant string)
(error variable function)))
;; Tree-sitter-css, for whatever reason, cannot reliably return
;; the captured nodes in a given range (it instead returns the
;; nodes preceding range). Before this is fixed in
;; tree-sitter-css, use this heuristic as a temporary fix.
(setq-local treesit--font-lock-query-expand-range (cons 80 80))
(setq-local imenu-create-index-function #'css--treesit-imenu)
(setq-local which-func-functions nil)
(treesit-major-mode-setup)))

View file

@ -498,6 +498,19 @@ omitted, default END to BEG."
"Generic tree-sitter font-lock error"
'treesit-error)
(defvar-local treesit--font-lock-query-expand-range (cons 0 0)
"The amount to expand the start and end of the region when fontifying.
This should be a cons cell (START . END). When fontifying a
buffer, Emacs will move the start of the query range backward by
START amount, and the end of the query range by END amount. Both
START and END should be positive integers or 0. This doesn't
affect the fontified range.
Sometimes, querying on some parser with a restricted range
returns nodes not in that range but before it, which breaks
fontification. Major modes can adjust this variable as a
temporarily fix.")
(defvar-local treesit-font-lock-feature-list nil
"A list of lists of feature symbols.
@ -817,14 +830,17 @@ If LOUDLY is non-nil, display some debugging information."
;; quote node will not give us the string node. So we don't use
;; treesit-node-on: using the root node with a restricted range
;; is very fast anyway (even in large files of size ~10MB).
;; Plus, querying non-root nodes with restricted range sometimes
;; misses nodes in the range and returns nodes outside of that
;; range, using root node frees us from all those quirks.
;; Plus, querying the result of `treesit-node-on' could still
;; miss patterns even if we use some heuristic to enlarge the
;; node (how much to enlarge? to which extent?), its much safer
;; to just use the root node.
;;
;; Sometimes the source file has some errors that causes
;; tree-sitter to parse it into a enormously tall tree (10k
;; levels tall). In that case querying the root node is very
;; slow.
;; slow. So we try to get top-level nodes and query them. This
;; ensures that querying is fast everywhere else, except for the
;; problematic region.
(when-let ((nodes (list (treesit-buffer-root-node language)))
;; Only activate if ENABLE flag is t.
(activate (eq t enable)))
@ -837,11 +853,15 @@ If LOUDLY is non-nil, display some debugging information."
(car nodes) start end)))
(dolist (sub-node nodes)
(let ((start-time (current-time))
(captures (treesit-query-capture
sub-node query start end))
(end-time (current-time))
(inhibit-point-motion-hooks t))
(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))
(inhibit-point-motion-hooks t))
;; If for any query the query time is strangely long,
;; switch to fast mode (see comments above).
(when (> (time-to-seconds (time-subtract end-time start-time))