The way we achieves this is thought parser notifiers. When tree-sitter
parser reparses, it notifies us of which part of the buffer was affected
by the reparse. For font-lock, we have this font-lock notifier that
marks the affected buffer region as "not fontified", so redisplay will
refontify those areas.
(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)))))
This notifier function will be called during redisplay [1]. I suspect
that because of this timing, redisplay doesn't refontify the marked
region immediately. So I added a timer, I think that ensures we mark the
affected region in the next command loop?
(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)))
(run-with-timer
0 nil
(lambda ()
(with-silent-modifications
(put-text-property (car range) (cdr range)
'fontified nil)))))))
This seems to work. Eli, do you see any problem using run-with-timer
this way? What's the correct way to mark some region unfontified?
[1] The chain of events if roughly: user types the last "/" -> redisplay
-> fontify that character -> access parser -> parser reparses -> calls
notifier.