Function: treesit-font-lock-fontify-region

treesit-font-lock-fontify-region is a byte-compiled function defined in treesit.el.gz.

Signature

(treesit-font-lock-fontify-region START END &optional LOUDLY)

Documentation

Fontify the region between START and END.

If LOUDLY is non-nil, display some debugging information.

Source Code

;; Defined in /usr/src/emacs/lisp/treesit.el.gz
;; Some details worth explaining:
;;
;; 1. When we apply face to a node, we clip the face into the
;; currently fontifying region, this way we don't overwrite faces
;; applied by regexp-based font-lock.  The clipped part will be
;; fontified fine when Emacs fontifies the region containing it.
;;
;; 2. 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.  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 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?), it's much safer to just use the root node.
;;
;; Sometimes the source file has some errors that cause tree-sitter to
;; parse it into a enormously tall tree (10k levels tall).  In that
;; case querying the root node is very 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.  (Bug#59415).
;;
;; Some other time the source file has a top-level node that contains
;; a huge number of immediate children (say, 10k children), querying
;; that node is also very slow, so instead of getting the top-level
;; node, we recursively go down the tree to find nodes that cover the
;; region but are reasonably small.  (Bug#59738).
;;
;; 3. It is possible to capture a node that's completely outside the
;; region between START and END: as long as the whole pattern
;; intersects the region, all the captured nodes in that pattern are
;; returned.  If the node is outside of that region, (max node-start
;; start) and friends return bad values, so we filter them out.
;; However, we don't filter these nodes out if a function will process
;; the node, because it could (and often do) fontify the relatives of
;; the captured node, not just the node itself.  If we took out those
;; nodes author of those functions would be very confused.
(defun treesit-font-lock-fontify-region (start end &optional loudly)
  "Fontify the region between START and END.
If LOUDLY is non-nil, display some debugging information."
  (when (or loudly treesit--font-lock-verbose)
    (message "Fontifying region: %s-%s" start end))
  (treesit-update-ranges start end)
  (font-lock-unfontify-region start end)
  (dolist (setting treesit-font-lock-settings)
    (let* ((query (nth 0 setting))
           (enable (nth 1 setting))
           (override (nth 3 setting))
           (language (treesit-query-language query)))

      ;; 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.
                  (activate (eq t enable)))
        (ignore activate)

        ;; Query each node.
        (dolist (sub-node nodes)
          (let* ((delta-start (car treesit--font-lock-query-expand-range))
                 (delta-end (cdr treesit--font-lock-query-expand-range))
                 (captures (treesit-query-capture
                            sub-node query
                            (max (- start delta-start) (point-min))
                            (min (+ end delta-end) (point-max)))))

            ;; For each captured node, fontify that node.
            (with-silent-modifications
              (dolist (capture captures)
                (let* ((face (car capture))
                       (node (cdr capture))
                       (node-start (treesit-node-start node))
                       (node-end (treesit-node-end node)))

                  ;; If node is not in the region, take them out.  See
                  ;; comment #3 above for more detail.
                  (if (and (facep face)
                           (or (>= start node-end) (>= node-start end)))
                      (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))

                    (cond
                     ((facep face)
                      (treesit-fontify-with-override
                       (max node-start start) (min node-end end)
                       face override))
                     ((functionp face)
                      (funcall face node override start end)))

                    ;; Don't raise an error if FACE is neither a face nor
                    ;; a function.  This is to allow intermediate capture
                    ;; names used for #match and #eq.
                    (when (or loudly treesit--font-lock-verbose)
                      (message "Fontifying text from %d to %d, Face: %s, Node: %s"
                               (max node-start start) (min node-end end)
                               face (treesit-node-type node))))))))))))
  `(jit-lock-bounds ,start . ,end))