aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuri Linkov2025-04-08 20:40:10 +0300
committerJuri Linkov2025-04-08 20:40:10 +0300
commit5e0daa1ef77d2a5fe5b65b8f0fa6c4eab83a2498 (patch)
tree965b088e71bd5a16aac576272078a08b006ee61d
parent7ff674d7125452b0ce6a8d39cb667eacb90f3df2 (diff)
downloademacs-5e0daa1ef77d2a5fe5b65b8f0fa6c4eab83a2498.tar.gz
emacs-5e0daa1ef77d2a5fe5b65b8f0fa6c4eab83a2498.zip
New function treesit-parsers-at for treesit-language-at (bug#77256).
* doc/lispref/parsing.texi (Multiple Languages): The variable 'treesit-language-at-point-function' is now optional for multi-language major modes. Add description of 'treesit-parsers-at'. * lisp/treesit.el (treesit-language-at-point-function): Change the the docstring to remove the dissuasion against deriving the language from parser ranges. (treesit-language-at): Use the first parser from 'treesit-parsers-at' as the default return value when 'treesit-language-at-point-function' is nil. Adapt the docstring. (treesit-node-at): Use 'treesit-parsers-at'. (treesit-parsers-at): New function. (treesit-local-parsers-at): Use 'treesit-parsers-at' with the most part of the body moved to it. (treesit-local-parsers-on): Replace the overlay property 'treesit-parser' with 'treesit-parser-local-p' in the docstring. (treesit-up-list, treesit-simple-imenu, treesit-outline-level): Use 'treesit-parsers-at'. * lisp/progmodes/c-ts-mode.el (c-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/progmodes/elixir-ts-mode.el (elixir-ts--treesit-language-at-point): Remove. (elixir-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/progmodes/js.el (js--treesit-language-at-point): Remove. (js-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/progmodes/php-ts-mode.el (php-ts-mode--html-language-at-point) (php-ts-mode--language-at-point): Remove. (php-ts-mode): Don't set 'treesit-language-at-point-function'. * lisp/textmodes/mhtml-ts-mode.el (mhtml-ts-mode--language-at-point): Remove. (mhtml-ts-mode): Don't set 'treesit-language-at-point-function'. Use 'treesit-language-at' for mode-line lighter.
-rw-r--r--doc/lispref/parsing.texi48
-rw-r--r--etc/NEWS29
-rw-r--r--lisp/progmodes/c-ts-mode.el2
-rw-r--r--lisp/progmodes/elixir-ts-mode.el15
-rw-r--r--lisp/progmodes/js.el17
-rw-r--r--lisp/progmodes/php-ts-mode.el28
-rw-r--r--lisp/textmodes/mhtml-ts-mode.el21
-rw-r--r--lisp/treesit.el118
8 files changed, 127 insertions, 151 deletions
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index 3e8e0851f2c..f7be47dc044 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -1814,12 +1814,12 @@ ranges for each parser are correct before using parsers in a buffer, and
1814call @code{treesit-language-at} to figure out the language responsible 1814call @code{treesit-language-at} to figure out the language responsible
1815for the text at some position. These two functions don't work by 1815for the text at some position. These two functions don't work by
1816themselves; they need major modes to set @code{treesit-range-settings} 1816themselves; they need major modes to set @code{treesit-range-settings}
1817and @code{treesit-language-at-point-function}, which do the actual work. 1817and optionally @code{treesit-language-at-point-function}, which do the actual work.
1818These functions and variables are explained in more detail towards the 1818These functions and variables are explained in more detail towards the
1819end of the section. 1819end of the section.
1820 1820
1821In short, multi-language major modes should set 1821In short, multi-language major modes should set
1822@code{treesit-primary-parser}, @code{treesit-range-settings}, and 1822@code{treesit-primary-parser}, @code{treesit-range-settings}, and optionally
1823@code{treesit-language-at-point-function} before calling 1823@code{treesit-language-at-point-function} before calling
1824@code{treesit-major-mode-setup}. 1824@code{treesit-major-mode-setup}.
1825 1825
@@ -1921,9 +1921,9 @@ This function returns the language of the text at buffer position
1921@var{pos}. Under the hood it calls 1921@var{pos}. Under the hood it calls
1922@code{treesit-language-at-point-function} and returns its return 1922@code{treesit-language-at-point-function} and returns its return
1923value. If @code{treesit-language-at-point-function} is @code{nil}, 1923value. If @code{treesit-language-at-point-function} is @code{nil},
1924this function returns the language of the first parser in the returned 1924this function returns the language of the deepest parser by embed level
1925value of @code{treesit-parser-list}. If there is no parser in the 1925among parsers returned by @code{treesit-parsers-at}. If there is no
1926buffer, it returns @code{nil}. 1926parser at that buffer position, it returns @code{nil}.
1927@end defun 1927@end defun
1928 1928
1929@heading Supporting multiple languages in major modes 1929@heading Supporting multiple languages in major modes
@@ -2011,7 +2011,7 @@ directly translate into operations shown above.
2011@end group 2011@end group
2012 2012
2013@group 2013@group
2014;; Major modes with multiple languages should always set 2014;; Major modes with multiple languages can optionally set
2015;; `treesit-language-at-point-function' (which see). 2015;; `treesit-language-at-point-function' (which see).
2016(setq treesit-language-at-point-function 2016(setq treesit-language-at-point-function
2017 (lambda (pos) 2017 (lambda (pos)
@@ -2094,17 +2094,45 @@ language of the buffer text at @var{pos}. This variable is used by
2094@code{treesit-language-at}. 2094@code{treesit-language-at}.
2095@end defvar 2095@end defvar
2096 2096
2097@defun treesit-local-parsers-at &optional pos language 2097@defun treesit-parsers-at &optional pos language with-host only
2098This function returns all parsers at @var{pos} in the current buffer.
2099@var{pos} defaults to point. The returned parsers are sorted by the
2100decreasing embed level.
2101
2102If @var{language} is non-@code{nil}, return parsers only for that
2103language.
2104
2105If @var{with-host} is non-@code{nil}, return a list of
2106@w{@code{(@var{parser} . @var{host-parser})}} where @var{host-parser}
2107is the host parser which created the @var{parser}.
2108
2109If @var{only} is non-@code{nil}, return all parsers including the
2110primary parser.
2111
2112The argument @var{only} can be a list of symbols that specify what
2113parsers to include in the return value.
2114
2115If @var{only} contains the symbol @code{local}, include local parsers.
2116Local parsers are those which only parse a limited region marked by an
2117overlay with a non-@code{nil} @code{treesit-parser-local-p} property.
2118
2119If @var{only} contains the symbol @code{global}, include non-local parsers
2120excluding the primary parser.
2121
2122If @var{only} contains the symbol `primary', include the primary parser.
2123@end defun
2124
2125@defun treesit-local-parsers-at &optional pos language with-host
2098This function returns all the local parsers at @var{pos} in the 2126This function returns all the local parsers at @var{pos} in the
2099current buffer. @var{pos} defaults to point. 2127current buffer. @var{pos} defaults to point.
2100 2128
2101Local parsers are those which only parse a limited region marked by an 2129Local parsers are those which only parse a limited region marked by an
2102overlay with a non-@code{nil} @code{treesit-parser} property. If 2130overlay with a non-@code{nil} @code{treesit-parser-local-p} property.
2103@var{language} is non-@code{nil}, only return parsers for that 2131If @var{language} is non-@code{nil}, only return parsers for that
2104language. 2132language.
2105@end defun 2133@end defun
2106 2134
2107@defun treesit-local-parsers-on &optional beg end language 2135@defun treesit-local-parsers-on &optional beg end language with-host
2108This function is the same as @code{treesit-local-parsers-at}, but it 2136This function is the same as @code{treesit-local-parsers-at}, but it
2109returns the local parsers in the range between @var{beg} and @var{end} 2137returns the local parsers in the range between @var{beg} and @var{end}
2110instead of at point. 2138instead of at point.
diff --git a/etc/NEWS b/etc/NEWS
index c08b0052639..fa8b0bf89a8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1995,18 +1995,6 @@ multi-language major mode it is sometimes necessary to modify rules from
1995one of the major modes to better suit the new multilingual context. 1995one of the major modes to better suit the new multilingual context.
1996 1996
1997+++ 1997+++
1998*** New command 'treesit-explore'.
1999This command replaces 'treesit-explore-mode'. It turns on
2000'treesit-explore-mode' if it’s not on, and pops up the explorer buffer
2001if it’s already on.
2002
2003+++
2004*** 'treesit-explore-mode' now supports local parsers.
2005Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser
2006rather than a language, and it’s now possible to select a local parser
2007at point to explore.
2008
2009+++
2010*** New variable 'treesit-aggregated-simple-imenu-settings'. 1998*** New variable 'treesit-aggregated-simple-imenu-settings'.
2011This variable allows major modes to setup Imenu for multiple languages. 1999This variable allows major modes to setup Imenu for multiple languages.
2012 2000
@@ -2024,6 +2012,23 @@ Users can customize this variable to add simple custom indentation rules
2024for tree-sitter major modes. 2012for tree-sitter major modes.
2025 2013
2026+++ 2014+++
2015*** 'treesit-language-at-point-function' is now optional.
2016Multi-language major modes can rely on the default return value from
2017'treesit-language-at' that uses the new function 'treesit-parsers-at'.
2018
2019+++
2020*** New command 'treesit-explore'.
2021This command replaces 'treesit-explore-mode'. It turns on
2022'treesit-explore-mode' if it’s not on, and pops up the explorer buffer
2023if it’s already on.
2024
2025+++
2026*** 'treesit-explore-mode' now supports local parsers.
2027Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser
2028rather than a language, and it’s now possible to select a local parser
2029at point to explore.
2030
2031+++
2027** New optional BUFFER argument for 'string-pixel-width'. 2032** New optional BUFFER argument for 'string-pixel-width'.
2028If supplied, 'string-pixel-width' will use any face remappings from 2033If supplied, 'string-pixel-width' will use any face remappings from
2029BUFFER when computing the string's width. 2034BUFFER when computing the string's width.
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index fa5f8567b60..c49e928884a 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -1488,8 +1488,6 @@ in your init files."
1488 (setq-local treesit-range-settings 1488 (setq-local treesit-range-settings
1489 (treesit-range-rules 'c-ts-mode--emacs-set-ranges)) 1489 (treesit-range-rules 'c-ts-mode--emacs-set-ranges))
1490 1490
1491 (setq-local treesit-language-at-point-function
1492 (lambda (_pos) 'c))
1493 (treesit-font-lock-recompute-features '(emacs-devel))) 1491 (treesit-font-lock-recompute-features '(emacs-devel)))
1494 1492
1495 ;; Inject doxygen parser for comment. 1493 ;; Inject doxygen parser for comment.
diff --git a/lisp/progmodes/elixir-ts-mode.el b/lisp/progmodes/elixir-ts-mode.el
index d50692d87c0..9a0418eaf29 100644
--- a/lisp/progmodes/elixir-ts-mode.el
+++ b/lisp/progmodes/elixir-ts-mode.el
@@ -596,18 +596,6 @@ With ARG, do it many times. Negative ARG means move backward."
596 (back-to-indentation) 596 (back-to-indentation)
597 (point))) 597 (point)))
598 598
599(defun elixir-ts--treesit-language-at-point (point)
600 "Return the language at POINT."
601 (let ((node (treesit-node-at point 'elixir)))
602 (if (and (equal (treesit-node-type node) "quoted_content")
603 (let ((prev-sibling (treesit-node-prev-sibling node t)))
604 (and (treesit-node-p prev-sibling)
605 (string-match-p
606 (rx bos (or "H" "F") eos)
607 (treesit-node-text prev-sibling)))))
608 'heex
609 'elixir)))
610
611(defun elixir-ts--defun-p (node) 599(defun elixir-ts--defun-p (node)
612 "Return non-nil when NODE is a defun." 600 "Return non-nil when NODE is a defun."
613 (member (treesit-node-text 601 (member (treesit-node-text
@@ -702,9 +690,6 @@ Return nil if NODE is not a defun node or doesn't have a name."
702 (setq-local treesit-primary-parser 690 (setq-local treesit-primary-parser
703 (treesit-parser-create 'elixir)) 691 (treesit-parser-create 'elixir))
704 692
705 (setq-local treesit-language-at-point-function
706 'elixir-ts--treesit-language-at-point)
707
708 ;; Font-lock. 693 ;; Font-lock.
709 (setq-local treesit-font-lock-settings elixir-ts--font-lock-settings) 694 (setq-local treesit-font-lock-settings elixir-ts--font-lock-settings)
710 (setq-local treesit-font-lock-feature-list 695 (setq-local treesit-font-lock-feature-list
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index f319d1d2fa9..69d05feb594 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3730,22 +3730,6 @@ Return nil if there is no name or if NODE is not a defun node."
3730 eos)))) 3730 eos))))
3731 (_ t))) 3731 (_ t)))
3732 3732
3733(defun js--treesit-language-at-point (point)
3734 "Return the language at POINT."
3735 (let* ((node (treesit-node-at point 'javascript))
3736 (node-type (treesit-node-type node))
3737 (node-start (treesit-node-start node))
3738 (node-end (treesit-node-end node)))
3739 (if (not (treesit-ready-p 'jsdoc t))
3740 'javascript
3741 (if (equal node-type "comment")
3742 (save-excursion
3743 (goto-char node-start)
3744 (if (search-forward "/**" node-end t)
3745 'jsdoc
3746 'javascript))
3747 'javascript))))
3748
3749;;; Main Function 3733;;; Main Function
3750 3734
3751;;;###autoload 3735;;;###autoload
@@ -4006,7 +3990,6 @@ See `treesit-thing-settings' for more information.")
4006 3990
4007 ;; Tree-sitter setup. 3991 ;; Tree-sitter setup.
4008 (setq-local treesit-primary-parser (treesit-parser-create 'javascript)) 3992 (setq-local treesit-primary-parser (treesit-parser-create 'javascript))
4009 (setq-local treesit-language-at-point-function #'js--treesit-language-at-point)
4010 3993
4011 ;; Indent. 3994 ;; Indent.
4012 (setq-local treesit-simple-indent-rules js--treesit-indent-rules) 3995 (setq-local treesit-simple-indent-rules js--treesit-indent-rules)
diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el
index fb5cf46f9e5..33c44693cf4 100644
--- a/lisp/progmodes/php-ts-mode.el
+++ b/lisp/progmodes/php-ts-mode.el
@@ -1150,32 +1150,6 @@ For NODE, OVERRIDE, START, and END, see `treesit-font-lock-rules'."
1150 'font-lock-warning-face 1150 'font-lock-warning-face
1151 override start end)) 1151 override start end))
1152 1152
1153(defun php-ts-mode--html-language-at-point (point)
1154 "Return the language at POINT assuming the point is within a HTML region."
1155 (let* ((node (treesit-node-at point 'html))
1156 (parent (treesit-node-parent node))
1157 (node-query (format "(%s (%s))"
1158 (treesit-node-type parent)
1159 (treesit-node-type node))))
1160 (cond
1161 ((string-equal "(script_element (raw_text))" node-query) 'javascript)
1162 ((string-equal "(style_element (raw_text))" node-query) 'css)
1163 (t 'html))))
1164
1165(defun php-ts-mode--language-at-point (point)
1166 "Return the language at POINT."
1167 (let* ((node (treesit-node-at point 'php))
1168 (node-type (treesit-node-type node))
1169 (parent (treesit-node-parent node))
1170 (node-query (format "(%s (%s))" (treesit-node-type parent) node-type)))
1171 (save-excursion
1172 (goto-char (treesit-node-start node))
1173 (cond
1174 ((not (member node-query '("(program (text))"
1175 "(text_interpolation (text))")))
1176 'php)
1177 (t (php-ts-mode--html-language-at-point point))))))
1178
1179 1153
1180;;; Imenu 1154;;; Imenu
1181 1155
@@ -1466,8 +1440,6 @@ Depends on `c-ts-common-comment-setup'."
1466 (start_tag (tag_name)) 1440 (start_tag (tag_name))
1467 (raw_text) @cap)))) 1441 (raw_text) @cap))))
1468 1442
1469 (setq-local treesit-language-at-point-function #'php-ts-mode--language-at-point)
1470
1471 ;; Navigation. 1443 ;; Navigation.
1472 (setq-local treesit-defun-type-regexp 1444 (setq-local treesit-defun-type-regexp
1473 (regexp-opt '("class_declaration" 1445 (regexp-opt '("class_declaration"
diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el
index 25af6a0a1e0..0c98ec472b2 100644
--- a/lisp/textmodes/mhtml-ts-mode.el
+++ b/lisp/textmodes/mhtml-ts-mode.el
@@ -211,21 +211,6 @@ Optional ARGUMENTS to to be passed to it."
211 "Menu bar for `mhtml-ts-mode'." 211 "Menu bar for `mhtml-ts-mode'."
212 css-mode--menu) 212 css-mode--menu)
213 213
214;; To enable some basic treesiter functionality, you should define
215;; a function that recognizes which grammar is used at-point.
216;; This function should be assigned to `treesit-language-at-point-function'
217(defun mhtml-ts-mode--language-at-point (point)
218 "Return the language at POINT assuming the point is within a HTML buffer."
219 (let* ((node (treesit-node-at point 'html))
220 (parent (treesit-node-parent node))
221 (node-query (format "(%s (%s))"
222 (treesit-node-type parent)
223 (treesit-node-type node))))
224 (cond
225 ((equal "(script_element (raw_text))" node-query) (js--treesit-language-at-point point))
226 ((equal "(style_element (raw_text))" node-query) 'css)
227 (t 'html))))
228
229;; Custom font-lock function that's used to apply color to css color 214;; Custom font-lock function that's used to apply color to css color
230;; The signature of the function should be conforming to signature 215;; The signature of the function should be conforming to signature
231;; QUERY-SPEC required by `treesit-font-lock-rules'. 216;; QUERY-SPEC required by `treesit-font-lock-rules'.
@@ -440,7 +425,7 @@ Calls REPORT-FN directly. Requires tidy."
440 425
441;;;###autoload 426;;;###autoload
442(define-derived-mode mhtml-ts-mode html-ts-mode 427(define-derived-mode mhtml-ts-mode html-ts-mode
443 '("HTML+" (:eval (let ((lang (mhtml-ts-mode--language-at-point (point)))) 428 '("HTML+" (:eval (let ((lang (treesit-language-at (point))))
444 (cond ((eq lang 'html) "") 429 (cond ((eq lang 'html) "")
445 ((eq lang 'javascript) "JS") 430 ((eq lang 'javascript) "JS")
446 ((eq lang 'css) "CSS"))))) 431 ((eq lang 'css) "CSS")))))
@@ -514,10 +499,6 @@ Powered by tree-sitter."
514 (setq-local c-ts-common--comment-regexp 499 (setq-local c-ts-common--comment-regexp
515 js--treesit-jsdoc-comment-regexp)) 500 js--treesit-jsdoc-comment-regexp))
516 501
517
518 ;; Many treesit functions need to know the language at-point.
519 ;; So you should define such a function.
520 (setq-local treesit-language-at-point-function #'mhtml-ts-mode--language-at-point)
521 (setq-local prettify-symbols-alist mhtml-ts-mode--prettify-symbols-alist) 502 (setq-local prettify-symbols-alist mhtml-ts-mode--prettify-symbols-alist)
522 503
523 ;; Indent. 504 ;; Indent.
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 07861603244..888f067e0cc 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -174,26 +174,19 @@ The function is called with one argument, the position of point.
174 174
175In general, this function should call `treesit-node-at' with an 175In general, this function should call `treesit-node-at' with an
176explicit language (usually the host language), and determine the 176explicit language (usually the host language), and determine the
177language at point using the type of the returned node. 177language at point using the type of the returned node.")
178
179DO NOT derive the language at point from parser ranges. It's
180cumbersome and can't deal with some edge cases.")
181 178
182(defun treesit-language-at (position) 179(defun treesit-language-at (position)
183 "Return the language at POSITION. 180 "Return the language at POSITION.
184 181
185This function assumes that parser ranges are up-to-date. It 182When there are multiple parsers that covers POSITION, determine
186returns the return value of `treesit-language-at-point-function' 183the most relevant parser (hence language) by their embed level.
187if it's non-nil, otherwise it returns the language of the first 184If `treesit-language-at-point-function' is non-nil, return
188parser in `treesit-parser-list', or nil if there is no parser. 185the return value of that function instead."
189
190In a multi-language buffer, make sure
191`treesit-language-at-point-function' is implemented! Otherwise
192`treesit-language-at' wouldn't return the correct result."
193 (if treesit-language-at-point-function 186 (if treesit-language-at-point-function
194 (funcall treesit-language-at-point-function position) 187 (funcall treesit-language-at-point-function position)
195 (when-let* ((parser (car (treesit-parser-list)))) 188 (treesit-parser-language
196 (treesit-parser-language parser)))) 189 (car (treesit-parsers-at position)))))
197 190
198;;; Node API supplement 191;;; Node API supplement
199 192
@@ -247,8 +240,9 @@ language and doesn't match the language of the local parser."
247 (parser-or-lang 240 (parser-or-lang
248 (let* ((local-parser (car (treesit-local-parsers-at 241 (let* ((local-parser (car (treesit-local-parsers-at
249 pos parser-or-lang))) 242 pos parser-or-lang)))
250 (global-parser (car (treesit-parser-list 243 (global-parser (car (treesit-parsers-at
251 nil parser-or-lang))) 244 pos parser-or-lang nil
245 '(primary global))))
252 (parser (or local-parser global-parser))) 246 (parser (or local-parser global-parser)))
253 (when parser 247 (when parser
254 (treesit-parser-root-node parser)))) 248 (treesit-parser-root-node parser))))
@@ -267,13 +261,10 @@ language and doesn't match the language of the local parser."
267 (local-parser 261 (local-parser
268 ;; Find the local parser with highest 262 ;; Find the local parser with highest
269 ;; embed-level at point. 263 ;; embed-level at point.
270 (car (seq-sort-by #'treesit-parser-embed-level 264 (car (treesit-local-parsers-at pos lang)))
271 (lambda (a b) 265 (global-parser (car (treesit-parsers-at
272 (> (or a 0) (or b 0))) 266 pos lang nil
273 (treesit-local-parsers-at 267 '(primary global))))
274 pos lang))))
275 (global-parser (car (treesit-parser-list
276 nil lang)))
277 (parser (or local-parser global-parser))) 268 (parser (or local-parser global-parser)))
278 (when parser 269 (when parser
279 (treesit-parser-root-node parser)))))) 270 (treesit-parser-root-node parser))))))
@@ -851,30 +842,68 @@ those inside are kept."
851 if (<= start (car range) (cdr range) end) 842 if (<= start (car range) (cdr range) end)
852 collect range)) 843 collect range))
853 844
845(defun treesit-parsers-at (&optional pos language with-host only)
846 "Return all parsers at POS.
847
848POS defaults to point. The returned parsers are sorted by
849the decreasing embed level.
850
851If LANGUAGE is non-nil, only return parsers for LANGUAGE.
852
853If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER)
854instead. HOST-PARSER is the host parser which created the PARSER.
855
856If ONLY is nil, return all parsers including the primary parser.
857
858The argument ONLY can be a list of symbols that specify what
859parsers to include in the return value.
860
861If ONLY contains the symbol `local', include local parsers.
862Local parsers are those which only parse a limited region marked
863by an overlay with non-nil `treesit-parser-local-p' property.
864
865If ONLY contains the symbol `global', include non-local parsers
866excluding the primary parser.
867
868If ONLY contains the symbol `primary', include the primary parser."
869 (let ((res nil))
870 ;; Refer to (ref:local-parser-overlay) for more explanation of local
871 ;; parser overlays.
872 (dolist (ov (overlays-at (or pos (point))))
873 (when-let* ((parser (overlay-get ov 'treesit-parser))
874 (host-parser (or (null with-host)
875 (overlay-get ov 'treesit-host-parser)))
876 (_ (or (null language)
877 (eq (treesit-parser-language parser)
878 language)))
879 (_ (or (null only)
880 (and (memq 'local only) (memq 'global only))
881 (and (memq 'local only)
882 (overlay-get ov 'treesit-parser-local-p))
883 (and (memq 'global only)
884 (not (overlay-get ov 'treesit-parser-local-p))))))
885 (push (if with-host (cons parser host-parser) parser) res)))
886 (when (or (null only) (memq 'primary only))
887 (setq res (cons treesit-primary-parser res)))
888 (seq-sort-by (lambda (p)
889 (treesit-parser-embed-level
890 (or (car-safe p) p)))
891 (lambda (a b)
892 (> (or a 0) (or b 0)))
893 res)))
894
854(defun treesit-local-parsers-at (&optional pos language with-host) 895(defun treesit-local-parsers-at (&optional pos language with-host)
855 "Return all the local parsers at POS. 896 "Return all the local parsers at POS.
856 897
857POS defaults to point. 898POS defaults to point.
858Local parsers are those which only parse a limited region marked 899Local parsers are those which only parse a limited region marked
859by an overlay with non-nil `treesit-parser' property. 900by an overlay with non-nil `treesit-parser-local-p' property.
860If LANGUAGE is non-nil, only return parsers for LANGUAGE. 901If LANGUAGE is non-nil, only return parsers for LANGUAGE.
861 902
862If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) 903If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER)
863instead. HOST-PARSER is the host parser which created the local 904instead. HOST-PARSER is the host parser which created the local
864PARSER." 905PARSER."
865 (let ((res nil)) 906 (treesit-parsers-at pos language with-host '(local)))
866 ;; Refer to (ref:local-parser-overlay) for more explanation of local
867 ;; parser overlays.
868 (dolist (ov (overlays-at (or pos (point))))
869 (let ((parser (overlay-get ov 'treesit-parser))
870 (host-parser (overlay-get ov 'treesit-host-parser))
871 (local-p (overlay-get ov 'treesit-parser-local-p)))
872 (when (and parser host-parser local-p
873 (or (null language)
874 (eq (treesit-parser-language parser)
875 language)))
876 (push (if with-host (cons parser host-parser) parser) res))))
877 (nreverse res)))
878 907
879(defun treesit-local-parsers-on (&optional beg end language with-host) 908(defun treesit-local-parsers-on (&optional beg end language with-host)
880 "Return the list of local parsers that cover the region between BEG and END. 909 "Return the list of local parsers that cover the region between BEG and END.
@@ -883,7 +912,7 @@ BEG and END default to the beginning and end of the buffer's accessible
883portion. 912portion.
884 913
885Local parsers are those that have an `embedded' tag, and only parse a 914Local parsers are those that have an `embedded' tag, and only parse a
886limited region marked by an overlay with a non-nil `treesit-parser' 915limited region marked by an overlay with a non-nil `treesit-parser-local-p'
887property. If LANGUAGE is non-nil, only return parsers for LANGUAGE. 916property. If LANGUAGE is non-nil, only return parsers for LANGUAGE.
888 917
889If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) 918If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER)
@@ -3139,9 +3168,7 @@ ARG is described in the docstring of `up-list'."
3139 (setq parent (treesit-parent-until parent pred))) 3168 (setq parent (treesit-parent-until parent pred)))
3140 3169
3141 (unless parent 3170 (unless parent
3142 (let ((parsers (seq-keep (lambda (o) 3171 (let ((parsers (mapcar #'cdr (treesit-parsers-at (point) nil t '(global local)))))
3143 (overlay-get o 'treesit-host-parser))
3144 (overlays-at (point) t))))
3145 (while (and (not parent) parsers) 3172 (while (and (not parent) parsers)
3146 (setq parent (treesit-parent-until 3173 (setq parent (treesit-parent-until
3147 (treesit-node-at (point) (car parsers)) pred) 3174 (treesit-node-at (point) (car parsers)) pred)
@@ -3891,9 +3918,8 @@ by `treesit-simple-imenu-settings'."
3891 (lambda (entry) 3918 (lambda (entry)
3892 (let* ((lang (car entry)) 3919 (let* ((lang (car entry))
3893 (settings (cdr entry)) 3920 (settings (cdr entry))
3894 (global-parser (car (treesit-parser-list nil lang))) 3921 (global-parser (car (treesit-parsers-at nil lang nil '(primary global))))
3895 (local-parsers 3922 (local-parsers (treesit-local-parsers-at nil lang)))
3896 (treesit-parser-list nil lang 'embedded)))
3897 (cons (treesit-language-display-name lang) 3923 (cons (treesit-language-display-name lang)
3898 ;; No one says you can't have both global and local 3924 ;; No one says you can't have both global and local
3899 ;; parsers for the same language. E.g., Rust uses 3925 ;; parsers for the same language. E.g., Rust uses
@@ -4033,9 +4059,7 @@ For BOUND, MOVE, BACKWARD, LOOKING-AT, see the descriptions in
4033 (setq level (1+ level))) 4059 (setq level (1+ level)))
4034 4060
4035 ;; Continue counting the host nodes. 4061 ;; Continue counting the host nodes.
4036 (dolist (parser (seq-keep (lambda (o) 4062 (dolist (parser (mapcar #'cdr (treesit-parsers-at (point) nil t '(global local))))
4037 (overlay-get o 'treesit-host-parser))
4038 (overlays-at (point) t)))
4039 (let* ((node (treesit-node-at (point) parser)) 4063 (let* ((node (treesit-node-at (point) parser))
4040 (lang (treesit-parser-language parser)) 4064 (lang (treesit-parser-language parser))
4041 (pred (alist-get lang treesit-aggregated-outline-predicate))) 4065 (pred (alist-get lang treesit-aggregated-outline-predicate)))