aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuan Fu2025-07-08 23:15:58 -0700
committerYuan Fu2025-07-08 23:39:39 -0700
commit159ddd27ee6b6c8cd261c6ff495e66ddb6166685 (patch)
treee30d2362d09e862144f679348c21302d73dc61ab
parent564b947745b2a685edcd93eb8f0d8825352030b8 (diff)
downloademacs-159ddd27ee6b6c8cd261c6ff495e66ddb6166685.tar.gz
emacs-159ddd27ee6b6c8cd261c6ff495e66ddb6166685.zip
Ditch the async range update in tree-sitter (bug#78402)
Right now in treesit-outline-search -> treesit-navigate-thing, a freshly created tree-sitter node becomes outdated within the function. I'm not sure _exactly_ how it happend, but it might look like this: we first get a node from, say, html parser, then get another node from, say, liquid parser. Creating the node from liquid parser causes a reparse which updated the range of the html parser, which rendered the html node outdated. There're several problems with the current design, let's start with the most obvious one: we add treesit--font-lock-mark-ranges-to-fontify as a notifier of the primar parser in treesit-major-mode-setup. Now, if a ts major mode inherits another major mode, treesit-major-mode-setup will be called twice, once in the parent mode and once in the child node, and two parsers will have the notifier. But treesit--font-lock-mark-ranges-to-fontify is designed to run only once. I believe this bug, together with some mysterious async execution order, led to the problems we saw in the bug report. My solution is to just make everything synchronous. So I added treesit-parser-changed-regions, and modified treesit--font-lock-mark-ranges-to-fontify to use it. Now we don't need to add the notifier to the primary parser anymore. I also applied the tree-sitter-outline change we discussed in the bug report. (Change to treesit-outline-search, and remove treesit--after-change.) * lisp/treesit.el: (treesit--font-lock-mark-ranges-to-fontify): Remove the unused PARSER arg. (treesit--pre-redisplay): Make use of treesit-parser-changed-regions. (treesit-outline-search): Call treesit--pre-redisplay in the beginning. (treesit--after-change): Remove function. (treesit-major-mode-setup): Don't add notifier to primary parser.
-rw-r--r--lisp/treesit.el30
1 files changed, 10 insertions, 20 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 893e21ec0c5..aef61d2e68b 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -2020,7 +2020,7 @@ Because `pre-redisplay-functions' could be called multiple times
2020during a single command loop, we use this variable to debounce 2020during a single command loop, we use this variable to debounce
2021calls to `treesit--pre-redisplay'.") 2021calls to `treesit--pre-redisplay'.")
2022 2022
2023(defun treesit--font-lock-mark-ranges-to-fontify (ranges _parser) 2023(defun treesit--font-lock-mark-ranges-to-fontify (ranges)
2024 "A notifier that marks ranges that needs refontification. 2024 "A notifier that marks ranges that needs refontification.
2025 2025
2026For RANGES and PARSER see `treesit-parser-add-notifier'. 2026For RANGES and PARSER see `treesit-parser-add-notifier'.
@@ -2074,17 +2074,15 @@ parser."
2074 (car (treesit-parser-list)))) 2074 (car (treesit-parser-list))))
2075 2075
2076(defun treesit--pre-redisplay (&rest _) 2076(defun treesit--pre-redisplay (&rest _)
2077 "Force a reparse on the primary parser and mark regions to be fontified. 2077 "Force a reparse on primary parser and mark regions to be fontified."
2078
2079The actual work is carried out by
2080`treesit--font-lock-mark-ranges-to-fontify', which see."
2081 (unless (eq treesit--pre-redisplay-tick (buffer-chars-modified-tick)) 2078 (unless (eq treesit--pre-redisplay-tick (buffer-chars-modified-tick))
2082 (when treesit-primary-parser 2079 (when treesit-primary-parser
2083 ;; Force a reparse on the primary parser, if everything is setup 2080 ;; Force a reparse on the primary parser and update embedded
2084 ;; correctly, the parser should call 2081 ;; parser ranges in the changed ranges.
2085 ;; `treesit--font-lock-mark-ranges-to-fontify' (which should be a 2082 (let ((affected-ranges (treesit-parser-changed-regions
2086 ;; notifier function of the primary parser). 2083 treesit-primary-parser)))
2087 (treesit-parser-root-node treesit-primary-parser)) 2084 (when affected-ranges
2085 (treesit--font-lock-mark-ranges-to-fontify affected-ranges))))
2088 2086
2089 (setq treesit--pre-redisplay-tick (buffer-chars-modified-tick)))) 2087 (setq treesit--pre-redisplay-tick (buffer-chars-modified-tick))))
2090 2088
@@ -4072,6 +4070,7 @@ this variable takes priority.")
4072 "Search for the next outline heading in the syntax tree. 4070 "Search for the next outline heading in the syntax tree.
4073For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in 4071For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in
4074`outline-search-function'." 4072`outline-search-function'."
4073 (treesit--pre-redisplay)
4075 (if looking-at 4074 (if looking-at
4076 (when (treesit-outline--at-point) (pos-bol)) 4075 (when (treesit-outline--at-point) (pos-bol))
4077 4076
@@ -4158,11 +4157,6 @@ For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in
4158 4157
4159 level)) 4158 level))
4160 4159
4161(defun treesit--after-change (beg end _len)
4162 "Force updating the ranges in BEG...END.
4163Expected to be called after each text change."
4164 (treesit-update-ranges beg end))
4165
4166;;; Hideshow mode 4160;;; Hideshow mode
4167 4161
4168(defun treesit-hs-block-end () 4162(defun treesit-hs-block-end ()
@@ -4374,9 +4368,6 @@ before calling this function."
4374 . treesit-font-lock-fontify-region))) 4368 . treesit-font-lock-fontify-region)))
4375 (treesit-font-lock-recompute-features) 4369 (treesit-font-lock-recompute-features)
4376 (add-hook 'pre-redisplay-functions #'treesit--pre-redisplay 0 t) 4370 (add-hook 'pre-redisplay-functions #'treesit--pre-redisplay 0 t)
4377 (when treesit-primary-parser
4378 (treesit-parser-add-notifier
4379 treesit-primary-parser #'treesit--font-lock-mark-ranges-to-fontify))
4380 (treesit-validate-font-lock-rules treesit-font-lock-settings)) 4371 (treesit-validate-font-lock-rules treesit-font-lock-settings))
4381 ;; Syntax 4372 ;; Syntax
4382 (add-hook 'syntax-propertize-extend-region-functions 4373 (add-hook 'syntax-propertize-extend-region-functions
@@ -4462,8 +4453,7 @@ before calling this function."
4462 (setq treesit-outline-predicate 4453 (setq treesit-outline-predicate
4463 #'treesit-outline-predicate--from-imenu)) 4454 #'treesit-outline-predicate--from-imenu))
4464 (setq-local outline-search-function #'treesit-outline-search 4455 (setq-local outline-search-function #'treesit-outline-search
4465 outline-level #'treesit-outline-level) 4456 outline-level #'treesit-outline-level))
4466 (add-hook 'outline-after-change-functions #'treesit--after-change nil t))
4467 4457
4468 ;; Remove existing local parsers. 4458 ;; Remove existing local parsers.
4469 (dolist (ov (overlays-in (point-min) (point-max))) 4459 (dolist (ov (overlays-in (point-min) (point-max)))