diff options
| author | Yuan Fu | 2025-03-11 00:44:49 -0700 |
|---|---|---|
| committer | Yuan Fu | 2025-03-11 01:06:39 -0700 |
| commit | 57a213c91cdf4b1739b1068c5dc8ae85f1d5302c (patch) | |
| tree | 2a42b764de76b4762f31eb18d45e24e3bd81822a | |
| parent | 03a6d4256f861d71e09206ac09d48f16efd52b64 (diff) | |
| download | emacs-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.el | 98 |
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) | |||
| 849 | instead. HOST-PARSER is the host parser which created the local | 863 | instead. HOST-PARSER is the host parser which created the local |
| 850 | PARSER." | 864 | PARSER." |
| 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) | |||
| 872 | instead. HOST-PARSER is the host parser which created the local | 890 | instead. HOST-PARSER is the host parser which created the local |
| 873 | PARSER." | 891 | PARSER." |
| 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." | |||
| 887 | For every local parser overlay between BEG and END, if its | 909 | For 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 |
| 889 | it." | 911 | it." |
| 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. | |||
| 923 | EMBED-LANG is either a language symbol or a function that takes a node | 949 | EMBED-LANG is either a language symbol or a function that takes a node |
| 924 | and returns a language symbol. | 950 | and returns a language symbol. |
| 925 | 951 | ||
| 952 | When this function touches an overlay, it sets the | ||
| 953 | `treesit-parser-ov-timestamp' property of the overlay to MODIFIED-TICK. | ||
| 954 | This will help Emacs garbage-collect overlays that aren't in use | ||
| 955 | anymore. | ||
| 956 | |||
| 926 | EMBED-LEVEL is the embed level for the local parsers being created or | 957 | EMBED-LEVEL is the embed level for the local parsers being created or |
| 927 | updated. When looking for existing local parsers, only look for parsers | 958 | updated. When looking for existing local parsers, only look for parsers |
| 928 | of this level; when creating new local parsers, set their level to this | 959 | of 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 |