aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuan Fu2025-03-11 00:44:49 -0700
committerYuan Fu2025-03-11 01:06:39 -0700
commit57a213c91cdf4b1739b1068c5dc8ae85f1d5302c (patch)
tree2a42b764de76b4762f31eb18d45e24e3bd81822a
parent03a6d4256f861d71e09206ac09d48f16efd52b64 (diff)
downloademacs-57a213c91cdf4b1739b1068c5dc8ae85f1d5302c.tar.gz
emacs-57a213c91cdf4b1739b1068c5dc8ae85f1d5302c.zip
Add overlays for non-local tree-sitter parsers too
* lisp/treesit.el (treesit-local-parsers-at): (treesit-local-parsers-on): Exclude non-local parsers. (treesit--cleanup-local-range-overlays): Don't delete non-local parsers (because those are managed by the major mode). (treesit--update-ranges-non-local): Apply overlay for each ranges. (treesit--update-ranges-local): Ignore overlays with non-local parsers, and set 'treesit-parser-local-p' property to t. (treesit--update-range-1): Additionally pass modified-tick to treesit--update-ranges-non-local. (treesit-major-mode-setup): Don't delete non-local parsers.
-rw-r--r--lisp/treesit.el98
1 files changed, 79 insertions, 19 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el
index c5c08f47dc3..36f26ea5825 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -629,6 +629,20 @@ If none are valid, return nil."
629 629
630;;; Range API supplement 630;;; Range API supplement
631 631
632;; (ref:local-parser-overlay) Regarding local parser overlays, we store
633;; the local parser in a overlay spanning across the code block that the
634;; parser is responsible of. The `treesit-parser' property stores the
635;; parser, the `treesit-host-parser' property stores the host parser,
636;; the `treesit-parser-ov-timestamp' property stores the buffer's tick
637;; counter (`buffer-modified-tick') when we last updated this overlay,
638;; it's used for garbage-collecting stale ranges and local parsers.
639;;
640;; Besides local parsers, we also create overlays for non-local parsers,
641;; just to mark the start and end of each range it parses, so that other
642;; functions can make use of this information. To differentiate the
643;; overlay for local and non-local parsers, local parsers' overlay has
644;; the `treesit-parser-local-p' property set to non-nil.
645
632(defvar-local treesit-range-settings nil 646(defvar-local treesit-range-settings nil
633 "A list of range settings. 647 "A list of range settings.
634 648
@@ -849,12 +863,16 @@ If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER)
849instead. HOST-PARSER is the host parser which created the local 863instead. HOST-PARSER is the host parser which created the local
850PARSER." 864PARSER."
851 (let ((res nil)) 865 (let ((res nil))
866 ;; Refer to (ref:local-parser-overlay) for more explanation of local
867 ;; parser overlays.
852 (dolist (ov (overlays-at (or pos (point)))) 868 (dolist (ov (overlays-at (or pos (point))))
853 (when-let* ((parser (overlay-get ov 'treesit-parser)) 869 (let ((parser (overlay-get ov 'treesit-parser))
854 (host-parser (overlay-get ov 'treesit-host-parser))) 870 (host-parser (overlay-get ov 'treesit-host-parser))
855 (when (or (null language) 871 (local-p (overlay-get ov 'treesit-parser-local-p)))
856 (eq (treesit-parser-language parser) 872 (when (and parser host-parser local-p
857 language)) 873 (or (null language)
874 (eq (treesit-parser-language parser)
875 language)))
858 (push (if with-host (cons parser host-parser) parser) res)))) 876 (push (if with-host (cons parser host-parser) parser) res))))
859 (nreverse res))) 877 (nreverse res)))
860 878
@@ -872,12 +890,16 @@ If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER)
872instead. HOST-PARSER is the host parser which created the local 890instead. HOST-PARSER is the host parser which created the local
873PARSER." 891PARSER."
874 (let ((res nil)) 892 (let ((res nil))
893 ;; Refer to (ref:local-parser-overlay) for more explanation of local
894 ;; parser overlays.
875 (dolist (ov (overlays-in (or beg (point-min)) (or end (point-max)))) 895 (dolist (ov (overlays-in (or beg (point-min)) (or end (point-max))))
876 (when-let* ((parser (overlay-get ov 'treesit-parser)) 896 (let ((parser (overlay-get ov 'treesit-parser))
877 (host-parser (overlay-get ov 'treesit-host-parser))) 897 (host-parser (overlay-get ov 'treesit-host-parser))
878 (when (or (null language) 898 (local-p (overlay-get ov 'treesit-parser-local-p)))
879 (eq (treesit-parser-language parser) 899 (when (and parser host-parser local-p
880 language)) 900 (or (null language)
901 (eq (treesit-parser-language parser)
902 language)))
881 (push (if with-host (cons parser host-parser) parser) res)))) 903 (push (if with-host (cons parser host-parser) parser) res))))
882 (nreverse res))) 904 (nreverse res)))
883 905
@@ -887,12 +909,16 @@ PARSER."
887For every local parser overlay between BEG and END, if its 909For every local parser overlay between BEG and END, if its
888`treesit-parser-ov-timestamp' is smaller than MODIFIED-TICK, delete 910`treesit-parser-ov-timestamp' is smaller than MODIFIED-TICK, delete
889it." 911it."
912 ;; Refer to (ref:local-parser-overlay) for more explanation of local
913 ;; parser overlays.
890 (dolist (ov (overlays-in beg end)) 914 (dolist (ov (overlays-in beg end))
891 (when-let* ((ov-timestamp 915 (when-let* ((ov-timestamp
892 (overlay-get ov 'treesit-parser-ov-timestamp))) 916 (overlay-get ov 'treesit-parser-ov-timestamp)))
893 (when (< ov-timestamp modified-tick) 917 (when (< ov-timestamp modified-tick)
894 (when-let* ((local-parser (overlay-get ov 'treesit-parser))) 918 (let ((local-parser (overlay-get ov 'treesit-parser))
895 (treesit-parser-delete local-parser)) 919 (local-p (overlay-get ov 'treesit-parser-local-p)))
920 (when (and local-p local-parser)
921 (treesit-parser-delete local-parser)))
896 (delete-overlay ov))))) 922 (delete-overlay ov)))))
897 923
898(defsubst treesit--parser-at-level (parsers level &optional include-null) 924(defsubst treesit--parser-at-level (parsers level &optional include-null)
@@ -910,7 +936,7 @@ is nil."
910(declare-function treesit-parser-embed-level "treesit.c") 936(declare-function treesit-parser-embed-level "treesit.c")
911 937
912(defun treesit--update-ranges-non-local 938(defun treesit--update-ranges-non-local
913 ( host-parser query embed-lang embed-level 939 ( host-parser query embed-lang modified-tick embed-level
914 &optional beg end offset range-fn) 940 &optional beg end offset range-fn)
915 "Update range for non-local parsers between BEG and END under HOST-PARSER. 941 "Update range for non-local parsers between BEG and END under HOST-PARSER.
916 942
@@ -923,6 +949,11 @@ those ranges. HOST-PARSER and QUERY must match.
923EMBED-LANG is either a language symbol or a function that takes a node 949EMBED-LANG is either a language symbol or a function that takes a node
924and returns a language symbol. 950and returns a language symbol.
925 951
952When this function touches an overlay, it sets the
953`treesit-parser-ov-timestamp' property of the overlay to MODIFIED-TICK.
954This will help Emacs garbage-collect overlays that aren't in use
955anymore.
956
926EMBED-LEVEL is the embed level for the local parsers being created or 957EMBED-LEVEL is the embed level for the local parsers being created or
927updated. When looking for existing local parsers, only look for parsers 958updated. When looking for existing local parsers, only look for parsers
928of this level; when creating new local parsers, set their level to this 959of this level; when creating new local parsers, set their level to this
@@ -954,6 +985,29 @@ Return updated parsers as a list."
954 (treesit-parser-list nil resolved-embed-lang) 985 (treesit-parser-list nil resolved-embed-lang)
955 embed-level 'include-null))))) 986 embed-level 'include-null)))))
956 (when embed-parser 987 (when embed-parser
988 ;; Lay an overlay over each range to mark the start & end of
989 ;; it for other functions to access (e.g., outline wants to
990 ;; know this). Refer to (ref:local-parser-overlay) for more
991 ;; explanation of local parser overlays.
992 (dolist (range new-ranges)
993 (let ((has-existing-ov nil))
994 (setq has-existing-ov
995 (catch 'done
996 (dolist (ov (overlays-in (car range) (cdr range)))
997 (when (eq (overlay-get ov 'treesit-parser)
998 embed-parser)
999 (move-overlay ov (car range) (cdr range))
1000 (overlay-put ov 'treesit-parser-ov-timestamp
1001 modified-tick)
1002 (throw 'done t)))))
1003 (unless has-existing-ov
1004 (let ((ov (make-overlay (car range) (cdr range))))
1005 (overlay-put ov 'treesit-parser embed-parser)
1006 (overlay-put ov 'treesit-parser-local-p nil)
1007 (overlay-put ov 'treesit-host-parser host-parser)
1008 (overlay-put ov 'treesit-parser-ov-timestamp
1009 modified-tick)))))
1010 ;; Set ranges for the embed parser.
957 (let* ((old-ranges (treesit-parser-included-ranges 1011 (let* ((old-ranges (treesit-parser-included-ranges
958 embed-parser)) 1012 embed-parser))
959 (set-ranges (treesit--clip-ranges 1013 (set-ranges (treesit--clip-ranges
@@ -1025,7 +1079,8 @@ Return the created local parsers as a list."
1025 embedded-parser)) 1079 embedded-parser))
1026 (parser-level (treesit-parser-embed-level 1080 (parser-level (treesit-parser-embed-level
1027 embedded-parser))) 1081 embedded-parser)))
1028 (when (and (eq parser-lang embedded-lang) 1082 (when (and (overlay-get ov 'treesit-parser-local-p)
1083 (eq parser-lang embedded-lang)
1029 (eq embed-level parser-level)) 1084 (eq embed-level parser-level))
1030 (treesit-parser-set-included-ranges 1085 (treesit-parser-set-included-ranges
1031 embedded-parser `((,beg . ,end))) 1086 embedded-parser `((,beg . ,end)))
@@ -1035,12 +1090,15 @@ Return the created local parsers as a list."
1035 (throw 'done embedded-parser))))))) 1090 (throw 'done embedded-parser)))))))
1036 (if existing-local-parser 1091 (if existing-local-parser
1037 (push existing-local-parser touched-parsers) 1092 (push existing-local-parser touched-parsers)
1038 ;; Create overlay and local parser. 1093 ;; Create overlay and local parser. Refer to
1094 ;; (ref:local-parser-overlay) for more explanation of
1095 ;; local parser overlays.
1039 (let ((embedded-parser (treesit-parser-create 1096 (let ((embedded-parser (treesit-parser-create
1040 embedded-lang nil t 'embedded)) 1097 embedded-lang nil t 'embedded))
1041 (ov (make-overlay beg end nil nil t))) 1098 (ov (make-overlay beg end nil nil t)))
1042 (treesit-parser-set-embed-level embedded-parser embed-level) 1099 (treesit-parser-set-embed-level embedded-parser embed-level)
1043 (overlay-put ov 'treesit-parser embedded-parser) 1100 (overlay-put ov 'treesit-parser embedded-parser)
1101 (overlay-put ov 'treesit-parser-local-p t)
1044 (overlay-put ov 'treesit-host-parser host-parser) 1102 (overlay-put ov 'treesit-host-parser host-parser)
1045 (overlay-put ov 'treesit-parser-ov-timestamp 1103 (overlay-put ov 'treesit-parser-ov-timestamp
1046 modified-tick) 1104 modified-tick)
@@ -1093,8 +1151,8 @@ Function range settings in SETTINGS are ignored."
1093 (t (setq touched-parsers 1151 (t (setq touched-parsers
1094 (append touched-parsers 1152 (append touched-parsers
1095 (treesit--update-ranges-non-local 1153 (treesit--update-ranges-non-local
1096 host-parser query embed-lang embed-level 1154 host-parser query embed-lang modified-tick
1097 beg end offset range-fn)))))))) 1155 embed-level beg end offset range-fn))))))))
1098 touched-parsers)) 1156 touched-parsers))
1099 1157
1100(defun treesit-update-ranges (&optional beg end) 1158(defun treesit-update-ranges (&optional beg end)
@@ -4274,8 +4332,10 @@ before calling this function."
4274 4332
4275 ;; Remove existing local parsers. 4333 ;; Remove existing local parsers.
4276 (dolist (ov (overlays-in (point-min) (point-max))) 4334 (dolist (ov (overlays-in (point-min) (point-max)))
4277 (when-let* ((parser (overlay-get ov 'treesit-parser))) 4335 (let ((parser (overlay-get ov 'treesit-parser))
4278 (treesit-parser-delete parser) 4336 (local-p (overlay-get ov 'treesit-parser-local-p)))
4337 (when (and parser local-p)
4338 (treesit-parser-delete parser))
4279 (delete-overlay ov)))) 4339 (delete-overlay ov))))
4280 4340
4281;;; Helpers 4341;;; Helpers