(max node-start start) (min node-end end)
face (treesit-node-type node)))))))))
-(defun treesit--font-lock-notifier (ranges parser)
- "Ensures updated parts of the parse-tree are refontified.
-RANGES is a list of (BEG . END) ranges, PARSER is the tree-sitter
-parser notifying of the change."
- (with-current-buffer (treesit-parser-buffer parser)
- (dolist (range ranges)
- (when treesit--font-lock-verbose
- (message "Notifier received range: %s-%s"
- (car range) (cdr range)))
- (with-silent-modifications
- (put-text-property (car range) (cdr range) 'fontified nil)))))
-
(defvar-local treesit--syntax-propertize-start nil
"If non-nil, next `syntax-propertize' should start at this position.
and that function sets this variable to the start of the affected
region.")
-(defun treesit--syntax-propertize-notifier (ranges parser)
- "Sets `treesit--syntax-propertize-start' to the smallest start.
-Specifically, the smallest start position among all the ranges in
-RANGES for PARSER."
- (with-current-buffer (treesit-parser-buffer parser)
- (when-let* ((range-starts (mapcar #'car ranges))
- (min-range-start
- (seq-reduce
- #'min (cdr range-starts) (car range-starts))))
- (if (null treesit--syntax-propertize-start)
- (setq treesit--syntax-propertize-start min-range-start)
- (setq treesit--syntax-propertize-start
- (min treesit--syntax-propertize-start min-range-start))))))
-
(defvar-local treesit--pre-redisplay-tick nil
"The last `buffer-chars-modified-tick' that we've processed.
Because `pre-redisplay-functions' could be called multiple times
calls to `treesit--pre-redisplay'.")
(defun treesit--pre-redisplay (&rest _)
- "Force reparse and consequently run all notifiers.
-
-One of the notifiers is `treesit--font-lock-notifier', which will
-mark the region whose syntax has changed to \"need to refontify\".
-
-For example, when the user types the final slash of a C block
-comment /* xxx */, not only do we need to fontify the slash, but
-also the whole block comment, which previously wasn't fontified
-as comment due to incomplete parse tree."
+ "Force a reparse on the primary parser and do some work.
+
+After the parser reparses, we get the changed ranges, and
+1) update non-primary parsers' ranges in the changed ranges
+2) mark these ranges as to-be-fontified,
+3) tell syntax-ppss to start reparsing from the min point of the ranges
+
+We need to mark to-be-fontified ranges before redisplay starts working,
+because sometimes the range edited by the user is not the only range
+that needs to be refontified. For example, when the user types the
+final slash of a C block comment /* xxx */, not only do we need to
+fontify the slash, but also the whole block comment, which previously
+wasn't fontified as comment due to incomplete parse tree."
(unless (eq treesit--pre-redisplay-tick (buffer-chars-modified-tick))
- ;; `treesit-update-ranges' will force the host language's parser to
- ;; reparse and set correct ranges for embedded parsers. Then
- ;; `treesit-parser-root-node' will force those parsers to reparse.
- (let ((len (+ (* (window-body-height) (window-body-width)) 800)))
- ;; FIXME: As a temporary fix, this prevents Emacs from updating
- ;; every single local parsers in the buffer every time there's an
- ;; edit. Moving forward, we need some way to properly track the
- ;; regions which need update on parser ranges, like what jit-lock
- ;; and syntax-ppss does.
- (treesit-update-ranges
- (max (point-min) (- (point) len))
- (min (point-max) (+ (point) len))))
- ;; Force repase on _all_ the parsers might not be necessary, but
- ;; this is probably the most robust way.
- (dolist (parser (treesit-parser-list))
- (treesit-parser-root-node parser))
+ (let ((primary-parser
+ ;; TODO: We need something less ugly than this for getting
+ ;; the primary parser/language.
+ (if treesit-range-settings
+ (let ((query (car (car treesit-range-settings))))
+ (if (treesit-query-p query)
+ (treesit-parser-create
+ (treesit-query-language query))
+ (car (treesit-parser-list))))
+ (car (treesit-parser-list)))))
+ ;; Force a reparse on the primary parser.
+ (treesit-parser-root-node primary-parser)
+ (dolist (range (treesit-parser-changed-ranges primary-parser))
+ ;; 1. Update ranges.
+ (treesit-update-ranges (car range) (cdr range))
+ ;; 2. Mark the changed ranges to be fontified.
+ (when treesit--font-lock-verbose
+ (message "Notifier received range: %s-%s"
+ (car range) (cdr range)))
+ (with-silent-modifications
+ (put-text-property (car range) (cdr range) 'fontified nil))
+ ;; 3. Set `treesit--syntax-propertize-start'.
+ (if (null treesit--syntax-propertize-start)
+ (setq treesit--syntax-propertize-start (car range))
+ (setq treesit--syntax-propertize-start
+ (min treesit--syntax-propertize-start (car range))))))
+
(setq treesit--pre-redisplay-tick (buffer-chars-modified-tick))))
(defun treesit--pre-syntax-ppss (start end)
(font-lock-fontify-syntactically-function
. treesit-font-lock-fontify-region)))
(treesit-font-lock-recompute-features)
- (dolist (parser (treesit-parser-list))
- (treesit-parser-add-notifier
- parser #'treesit--font-lock-notifier))
(add-hook 'pre-redisplay-functions #'treesit--pre-redisplay 0 t))
;; Syntax
- (dolist (parser (treesit-parser-list))
- (treesit-parser-add-notifier
- parser #'treesit--syntax-propertize-notifier))
(add-hook 'syntax-propertize-extend-region-functions
#'treesit--pre-syntax-ppss 0 t)
;; Indent.