summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuan Fu <casouri@gmail.com>2022-11-20 16:37:19 -0800
committerYuan Fu <casouri@gmail.com>2022-11-20 17:04:58 -0800
commit625ea08652053617034bf8ceee0d6cfae34f2dcc (patch)
tree6436a240112a08a5d2bd0141baa0989d509d0ec1
parent657947dc7cf01a13a4fa260691a6fa0147107950 (diff)
downloademacs-625ea08652053617034bf8ceee0d6cfae34f2dcc.tar.gz
emacs-625ea08652053617034bf8ceee0d6cfae34f2dcc.tar.bz2
emacs-625ea08652053617034bf8ceee0d6cfae34f2dcc.zip
Improve tree-sitter fontification on large buffers
* lisp/treesit.el (treesit--children-covering-range) (treesit--children-covering-range-recurse): New functions. They are not currently used but could be useful in the future, so I left them in place. (treesit-font-lock-fontify-region): * lisp/treesit.el (treesit-font-lock-fontify-region): Use the result of treesit-node-on instead of the root node.
-rw-r--r--lisp/treesit.el60
1 files changed, 52 insertions, 8 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 674c984dfe5..d65ad31b473 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -748,6 +748,37 @@ instead."
(remove-text-properties start end '(rear-nonsticky nil))
(put-text-property start end 'rear-nonsticky new-prop))))
+(defun treesit--children-covering-range (node start end)
+ "Return a list of children of NODE covering a range.
+The range is between START and END."
+ (let* ((child (treesit-node-first-child-for-pos node start))
+ (result (list child)))
+ (while (and (< (treesit-node-end child) end)
+ (setq child (treesit-node-next-sibling child)))
+ (push child result))
+ (nreverse result)))
+
+(defun treesit--children-covering-range-recurse (node start end threshold)
+ "Return a list of children of NODE covering a range.
+Recursively go down the parse tree and collect children, until
+all nodes in the returned list are smaller than THRESHOLD. The
+range is between START and END."
+ (let* ((child (treesit-node-first-child-for-pos node start))
+ result)
+ (while (and child (<= (treesit-node-start child) end))
+ ;; If child still too large, recurse down. Otherwise collect
+ ;; child.
+ (if (> (- (treesit-node-end child)
+ (treesit-node-start child))
+ threshold)
+ (dolist (r (treesit--children-covering-range-recurse
+ child start end threshold))
+ (push r result))
+ (push child result))
+ (setq child (treesit-node-next-sibling child)))
+ ;; If NODE has no child, keep NODE.
+ (or result node)))
+
;; Some details worth explaining:
;;
;; 1. When we apply face to a node, we clip the face into the
@@ -768,18 +799,31 @@ If LOUDLY is non-nil, display some debugging information."
(enable (nth 1 setting))
(override (nth 3 setting))
(language (treesit-query-language query)))
- ;; Why root node rather than (treesit-node-on start end)? If
- ;; you insert an ending quote into a buffer, jit-lock only wants
- ;; to fontify that single quote, and (treesit-node-on start end)
- ;; will give you that quote node. We want to capture the string
- ;; and apply string face to it, but querying on the quote node
- ;; will not give us the string node.
- (when-let ((root (treesit-buffer-root-node language))
+ ;; If you insert an ending quote into a buffer, jit-lock only
+ ;; wants to fontify that single quote, and (treesit-node-on
+ ;; start end) will give you that quote node. We want to capture
+ ;; the string and apply string face to it, but querying on the
+ ;; quote node will not give us the string node. OTOH, if you
+ ;; query the root node, it will be very slow in very large
+ ;; (MB's) buffers. So we still use `treesit-node-on', but try
+ ;; to enlarge it if the node seems small. (The threshold for
+ ;; small is arbitrary.) TODO: Sometimes the node returned by
+ ;; `treesit-node-on' is still much larger than the region we
+ ;; want to fontify. I tried to recursively go down to its
+ ;; children and get a set of smaller nodes that span the region.
+ ;; But this didn't work too well.
+ (when-let ((node-on (treesit-node-on start end language))
;; Only activate if ENABLE flag is t.
(activate (eq t enable)))
(ignore activate)
+ ;; The node seems small, enlarge it.
+ (while (and (< (- (treesit-node-end node-on)
+ (treesit-node-start node-on))
+ 40)
+ (treesit-node-parent node-on))
+ (setq node-on (treesit-node-parent node-on)))
(let ((captures (treesit-query-capture
- root query start end))
+ node-on query start end))
(inhibit-point-motion-hooks t))
(with-silent-modifications
(dolist (capture captures)