Use treesit-subtree-stat to determine treesit--font-lock-fast-mode

* lisp/treesit.el:
(treesit--children-covering-range-recurse): Return nil if LIMIT is
exceeded.
(treesit--font-lock-fast-mode): Change to a ternary value.
(treesit-font-lock-fontify-region): Enable fast mode based on the
result of treesit-subtree-stat.
This commit is contained in:
Yuan Fu 2023-01-29 00:07:46 -08:00
parent 382e018856
commit 1970726e26
No known key found for this signature in database
GPG key ID: 56E19BC57664A442

View file

@ -913,14 +913,15 @@ LIMIT is the recursion limit, which defaults to 100."
(push r result)) (push r result))
(push child result)) (push child result))
(setq child (treesit-node-next-sibling child))) (setq child (treesit-node-next-sibling child)))
;; If NODE has no child, keep NODE. ;; If NODE has no child, keep NODE. If LIMIT is exceeded, return
(or result (list node)))) ;; nil.
(or result (and (> limit 0) (list node)))))
(defsubst treesit--node-length (node) (defsubst treesit--node-length (node)
"Return the length of the text of NODE." "Return the length of the text of NODE."
(- (treesit-node-end node) (treesit-node-start 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. "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! This is not a general optimization and should be RARELY needed!
See comments in `treesit-font-lock-fontify-region' for more See comments in `treesit-font-lock-fontify-region' for more
@ -985,36 +986,34 @@ If LOUDLY is non-nil, display some debugging information."
(enable (nth 1 setting)) (enable (nth 1 setting))
(override (nth 3 setting)) (override (nth 3 setting))
(language (treesit-query-language query))) (language (treesit-query-language query)))
(when-let ((nodes (list (treesit-buffer-root-node language)))
;; 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. ;; Only activate if ENABLE flag is t.
(activate (eq t enable))) (activate (eq t enable)))
(ignore activate) (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))))
;; Query each node. ;; Query each node.
(dolist (sub-node nodes) (dolist (sub-node nodes)
(let* ((delta-start (car treesit--font-lock-query-expand-range)) (let* ((delta-start (car treesit--font-lock-query-expand-range))
(delta-end (cdr treesit--font-lock-query-expand-range)) (delta-end (cdr treesit--font-lock-query-expand-range))
(start-time (current-time))
(captures (treesit-query-capture (captures (treesit-query-capture
sub-node query sub-node query
(max (- start delta-start) (point-min)) (max (- start delta-start) (point-min))
(min (+ end delta-end) (point-max)))) (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)))
;; For each captured node, fontify that node. ;; For each captured node, fontify that node.
(with-silent-modifications (with-silent-modifications
@ -1023,12 +1022,14 @@ If LOUDLY is non-nil, display some debugging information."
(node (cdr capture)) (node (cdr capture))
(node-start (treesit-node-start node)) (node-start (treesit-node-start node))
(node-end (treesit-node-end node))) (node-end (treesit-node-end node)))
;; If node is not in the region, take them out. See ;; If node is not in the region, take them out. See
;; comment #3 above for more detail. ;; comment #3 above for more detail.
(if (and (facep face) (if (and (facep face)
(or (>= start node-end) (>= node-start end))) (or (>= start node-end) (>= node-start end)))
(when (or loudly treesit--font-lock-verbose) (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)) (message "Captured node %s(%s-%s) but it is outside of fontifing region" node node-start node-end))
(cond (cond
((facep face) ((facep face)
(treesit-fontify-with-override (treesit-fontify-with-override
@ -1036,6 +1037,7 @@ If LOUDLY is non-nil, display some debugging information."
face override)) face override))
((functionp face) ((functionp face)
(funcall face node override start end))) (funcall face node override start end)))
;; Don't raise an error if FACE is neither a face nor ;; Don't raise an error if FACE is neither a face nor
;; a function. This is to allow intermediate capture ;; a function. This is to allow intermediate capture
;; names used for #match and #eq. ;; names used for #match and #eq.