diff options
| author | Juri Linkov | 2025-04-08 20:40:10 +0300 |
|---|---|---|
| committer | Juri Linkov | 2025-04-08 20:40:10 +0300 |
| commit | 5e0daa1ef77d2a5fe5b65b8f0fa6c4eab83a2498 (patch) | |
| tree | 965b088e71bd5a16aac576272078a08b006ee61d | |
| parent | 7ff674d7125452b0ce6a8d39cb667eacb90f3df2 (diff) | |
| download | emacs-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.texi | 48 | ||||
| -rw-r--r-- | etc/NEWS | 29 | ||||
| -rw-r--r-- | lisp/progmodes/c-ts-mode.el | 2 | ||||
| -rw-r--r-- | lisp/progmodes/elixir-ts-mode.el | 15 | ||||
| -rw-r--r-- | lisp/progmodes/js.el | 17 | ||||
| -rw-r--r-- | lisp/progmodes/php-ts-mode.el | 28 | ||||
| -rw-r--r-- | lisp/textmodes/mhtml-ts-mode.el | 21 | ||||
| -rw-r--r-- | lisp/treesit.el | 118 |
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 | |||
| 1814 | call @code{treesit-language-at} to figure out the language responsible | 1814 | call @code{treesit-language-at} to figure out the language responsible |
| 1815 | for the text at some position. These two functions don't work by | 1815 | for the text at some position. These two functions don't work by |
| 1816 | themselves; they need major modes to set @code{treesit-range-settings} | 1816 | themselves; they need major modes to set @code{treesit-range-settings} |
| 1817 | and @code{treesit-language-at-point-function}, which do the actual work. | 1817 | and optionally @code{treesit-language-at-point-function}, which do the actual work. |
| 1818 | These functions and variables are explained in more detail towards the | 1818 | These functions and variables are explained in more detail towards the |
| 1819 | end of the section. | 1819 | end of the section. |
| 1820 | 1820 | ||
| 1821 | In short, multi-language major modes should set | 1821 | In 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 |
| 1923 | value. If @code{treesit-language-at-point-function} is @code{nil}, | 1923 | value. If @code{treesit-language-at-point-function} is @code{nil}, |
| 1924 | this function returns the language of the first parser in the returned | 1924 | this function returns the language of the deepest parser by embed level |
| 1925 | value of @code{treesit-parser-list}. If there is no parser in the | 1925 | among parsers returned by @code{treesit-parsers-at}. If there is no |
| 1926 | buffer, it returns @code{nil}. | 1926 | parser 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 |
| 2098 | This function returns all parsers at @var{pos} in the current buffer. | ||
| 2099 | @var{pos} defaults to point. The returned parsers are sorted by the | ||
| 2100 | decreasing embed level. | ||
| 2101 | |||
| 2102 | If @var{language} is non-@code{nil}, return parsers only for that | ||
| 2103 | language. | ||
| 2104 | |||
| 2105 | If @var{with-host} is non-@code{nil}, return a list of | ||
| 2106 | @w{@code{(@var{parser} . @var{host-parser})}} where @var{host-parser} | ||
| 2107 | is the host parser which created the @var{parser}. | ||
| 2108 | |||
| 2109 | If @var{only} is non-@code{nil}, return all parsers including the | ||
| 2110 | primary parser. | ||
| 2111 | |||
| 2112 | The argument @var{only} can be a list of symbols that specify what | ||
| 2113 | parsers to include in the return value. | ||
| 2114 | |||
| 2115 | If @var{only} contains the symbol @code{local}, include local parsers. | ||
| 2116 | Local parsers are those which only parse a limited region marked by an | ||
| 2117 | overlay with a non-@code{nil} @code{treesit-parser-local-p} property. | ||
| 2118 | |||
| 2119 | If @var{only} contains the symbol @code{global}, include non-local parsers | ||
| 2120 | excluding the primary parser. | ||
| 2121 | |||
| 2122 | If @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 | ||
| 2098 | This function returns all the local parsers at @var{pos} in the | 2126 | This function returns all the local parsers at @var{pos} in the |
| 2099 | current buffer. @var{pos} defaults to point. | 2127 | current buffer. @var{pos} defaults to point. |
| 2100 | 2128 | ||
| 2101 | Local parsers are those which only parse a limited region marked by an | 2129 | Local parsers are those which only parse a limited region marked by an |
| 2102 | overlay with a non-@code{nil} @code{treesit-parser} property. If | 2130 | overlay with a non-@code{nil} @code{treesit-parser-local-p} property. |
| 2103 | @var{language} is non-@code{nil}, only return parsers for that | 2131 | If @var{language} is non-@code{nil}, only return parsers for that |
| 2104 | language. | 2132 | language. |
| 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 |
| 2108 | This function is the same as @code{treesit-local-parsers-at}, but it | 2136 | This function is the same as @code{treesit-local-parsers-at}, but it |
| 2109 | returns the local parsers in the range between @var{beg} and @var{end} | 2137 | returns the local parsers in the range between @var{beg} and @var{end} |
| 2110 | instead of at point. | 2138 | instead of at point. |
| @@ -1995,18 +1995,6 @@ multi-language major mode it is sometimes necessary to modify rules from | |||
| 1995 | one of the major modes to better suit the new multilingual context. | 1995 | one of the major modes to better suit the new multilingual context. |
| 1996 | 1996 | ||
| 1997 | +++ | 1997 | +++ |
| 1998 | *** New command 'treesit-explore'. | ||
| 1999 | This command replaces 'treesit-explore-mode'. It turns on | ||
| 2000 | 'treesit-explore-mode' if it’s not on, and pops up the explorer buffer | ||
| 2001 | if it’s already on. | ||
| 2002 | |||
| 2003 | +++ | ||
| 2004 | *** 'treesit-explore-mode' now supports local parsers. | ||
| 2005 | Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser | ||
| 2006 | rather than a language, and it’s now possible to select a local parser | ||
| 2007 | at point to explore. | ||
| 2008 | |||
| 2009 | +++ | ||
| 2010 | *** New variable 'treesit-aggregated-simple-imenu-settings'. | 1998 | *** New variable 'treesit-aggregated-simple-imenu-settings'. |
| 2011 | This variable allows major modes to setup Imenu for multiple languages. | 1999 | This 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 | |||
| 2024 | for tree-sitter major modes. | 2012 | for tree-sitter major modes. |
| 2025 | 2013 | ||
| 2026 | +++ | 2014 | +++ |
| 2015 | *** 'treesit-language-at-point-function' is now optional. | ||
| 2016 | Multi-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'. | ||
| 2021 | This command replaces 'treesit-explore-mode'. It turns on | ||
| 2022 | 'treesit-explore-mode' if it’s not on, and pops up the explorer buffer | ||
| 2023 | if it’s already on. | ||
| 2024 | |||
| 2025 | +++ | ||
| 2026 | *** 'treesit-explore-mode' now supports local parsers. | ||
| 2027 | Now 'treesit-explore-mode' (or 'treesit-explore') prompts for a parser | ||
| 2028 | rather than a language, and it’s now possible to select a local parser | ||
| 2029 | at point to explore. | ||
| 2030 | |||
| 2031 | +++ | ||
| 2027 | ** New optional BUFFER argument for 'string-pixel-width'. | 2032 | ** New optional BUFFER argument for 'string-pixel-width'. |
| 2028 | If supplied, 'string-pixel-width' will use any face remappings from | 2033 | If supplied, 'string-pixel-width' will use any face remappings from |
| 2029 | BUFFER when computing the string's width. | 2034 | BUFFER 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 | ||
| 175 | In general, this function should call `treesit-node-at' with an | 175 | In general, this function should call `treesit-node-at' with an |
| 176 | explicit language (usually the host language), and determine the | 176 | explicit language (usually the host language), and determine the |
| 177 | language at point using the type of the returned node. | 177 | language at point using the type of the returned node.") |
| 178 | |||
| 179 | DO NOT derive the language at point from parser ranges. It's | ||
| 180 | cumbersome 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 | ||
| 185 | This function assumes that parser ranges are up-to-date. It | 182 | When there are multiple parsers that covers POSITION, determine |
| 186 | returns the return value of `treesit-language-at-point-function' | 183 | the most relevant parser (hence language) by their embed level. |
| 187 | if it's non-nil, otherwise it returns the language of the first | 184 | If `treesit-language-at-point-function' is non-nil, return |
| 188 | parser in `treesit-parser-list', or nil if there is no parser. | 185 | the return value of that function instead." |
| 189 | |||
| 190 | In 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 | |||
| 848 | POS defaults to point. The returned parsers are sorted by | ||
| 849 | the decreasing embed level. | ||
| 850 | |||
| 851 | If LANGUAGE is non-nil, only return parsers for LANGUAGE. | ||
| 852 | |||
| 853 | If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) | ||
| 854 | instead. HOST-PARSER is the host parser which created the PARSER. | ||
| 855 | |||
| 856 | If ONLY is nil, return all parsers including the primary parser. | ||
| 857 | |||
| 858 | The argument ONLY can be a list of symbols that specify what | ||
| 859 | parsers to include in the return value. | ||
| 860 | |||
| 861 | If ONLY contains the symbol `local', include local parsers. | ||
| 862 | Local parsers are those which only parse a limited region marked | ||
| 863 | by an overlay with non-nil `treesit-parser-local-p' property. | ||
| 864 | |||
| 865 | If ONLY contains the symbol `global', include non-local parsers | ||
| 866 | excluding the primary parser. | ||
| 867 | |||
| 868 | If 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 | ||
| 857 | POS defaults to point. | 898 | POS defaults to point. |
| 858 | Local parsers are those which only parse a limited region marked | 899 | Local parsers are those which only parse a limited region marked |
| 859 | by an overlay with non-nil `treesit-parser' property. | 900 | by an overlay with non-nil `treesit-parser-local-p' property. |
| 860 | If LANGUAGE is non-nil, only return parsers for LANGUAGE. | 901 | If LANGUAGE is non-nil, only return parsers for LANGUAGE. |
| 861 | 902 | ||
| 862 | If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) | 903 | If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) |
| 863 | instead. HOST-PARSER is the host parser which created the local | 904 | instead. HOST-PARSER is the host parser which created the local |
| 864 | PARSER." | 905 | PARSER." |
| 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 | |||
| 883 | portion. | 912 | portion. |
| 884 | 913 | ||
| 885 | Local parsers are those that have an `embedded' tag, and only parse a | 914 | Local parsers are those that have an `embedded' tag, and only parse a |
| 886 | limited region marked by an overlay with a non-nil `treesit-parser' | 915 | limited region marked by an overlay with a non-nil `treesit-parser-local-p' |
| 887 | property. If LANGUAGE is non-nil, only return parsers for LANGUAGE. | 916 | property. If LANGUAGE is non-nil, only return parsers for LANGUAGE. |
| 888 | 917 | ||
| 889 | If WITH-HOST is non-nil, return a list of (PARSER . HOST-PARSER) | 918 | If 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))) |