diff options
| author | Yuan Fu | 2025-02-27 03:05:26 -0800 |
|---|---|---|
| committer | Yuan Fu | 2025-02-27 17:22:03 -0800 |
| commit | 30e1508ef2d40e221736cea2c50c64941d7d2f0d (patch) | |
| tree | 4a57810159f99c6329277fe71cfb6cec432ae420 | |
| parent | 32da093e524d5e28945557701f7c50d7c4a898cd (diff) | |
| download | emacs-30e1508ef2d40e221736cea2c50c64941d7d2f0d.tar.gz emacs-30e1508ef2d40e221736cea2c50c64941d7d2f0d.zip | |
Add tree-sitter-parser-embed-level and parent-node
Add parser properties embed-level and parent-node. They'll be
help us implement arbitrarily nested embeded parser, and
navigation across embedded and host parsers, respectively.
* src/treesit.c:
(Ftreesit_parser_embed_level):
(Ftreesit_parser_set_embed_level):
(Ftreesit_parser_parent_node):
(Ftreesit_parser_set_parent_node): New functions.
| -rw-r--r-- | src/treesit.c | 69 | ||||
| -rw-r--r-- | src/treesit.h | 22 |
2 files changed, 91 insertions, 0 deletions
diff --git a/src/treesit.c b/src/treesit.c index 62606d99749..16308193bf5 100644 --- a/src/treesit.c +++ b/src/treesit.c | |||
| @@ -1367,6 +1367,8 @@ make_treesit_parser (Lisp_Object buffer, TSParser *parser, | |||
| 1367 | lisp_parser->after_change_functions = Qnil; | 1367 | lisp_parser->after_change_functions = Qnil; |
| 1368 | lisp_parser->tag = tag; | 1368 | lisp_parser->tag = tag; |
| 1369 | lisp_parser->last_set_ranges = Qnil; | 1369 | lisp_parser->last_set_ranges = Qnil; |
| 1370 | lisp_parser->embed_level = Qnil; | ||
| 1371 | lisp_parser->parent_node = Qnil; | ||
| 1370 | lisp_parser->buffer = buffer; | 1372 | lisp_parser->buffer = buffer; |
| 1371 | lisp_parser->parser = parser; | 1373 | lisp_parser->parser = parser; |
| 1372 | lisp_parser->tree = tree; | 1374 | lisp_parser->tree = tree; |
| @@ -1818,6 +1820,69 @@ DEFUN ("treesit-parser-tag", | |||
| 1818 | return XTS_PARSER (parser)->tag; | 1820 | return XTS_PARSER (parser)->tag; |
| 1819 | } | 1821 | } |
| 1820 | 1822 | ||
| 1823 | DEFUN ("treesit-parser-embed-level", | ||
| 1824 | Ftreesit_parser_embed_level, Streesit_parser_embed_level, | ||
| 1825 | 1, 1, 0, | ||
| 1826 | doc: /* Return PARSER's embed level. | ||
| 1827 | |||
| 1828 | The embed level can be either nil or a non-negative integer. A value of | ||
| 1829 | nil means the parser isn't part of the embedded parser tree. The | ||
| 1830 | primary parser has embed level 0, from it, each layer of embedded parser | ||
| 1831 | has +1 embed level. */) | ||
| 1832 | (Lisp_Object parser) | ||
| 1833 | { | ||
| 1834 | treesit_check_parser (parser); | ||
| 1835 | return XTS_PARSER (parser)->embed_level; | ||
| 1836 | } | ||
| 1837 | |||
| 1838 | /* TODO: Mention in manual, once the API stabilizes. */ | ||
| 1839 | DEFUN ("treesit-parser-set-embed-level", | ||
| 1840 | Ftreesit_parser_set_embed_level, Streesit_parser_set_embed_level, | ||
| 1841 | 2, 2, 0, | ||
| 1842 | doc: /* Set the embed level for PARSER to LEVEL. */) | ||
| 1843 | (Lisp_Object parser, Lisp_Object level) | ||
| 1844 | { | ||
| 1845 | treesit_check_parser (parser); | ||
| 1846 | if (!NILP (level)) | ||
| 1847 | { | ||
| 1848 | CHECK_NUMBER (level); | ||
| 1849 | if (XFIXNUM (level) < 0) | ||
| 1850 | xsignal (Qargs_out_of_range, list1 (level)); | ||
| 1851 | } | ||
| 1852 | |||
| 1853 | XTS_PARSER (parser)->embed_level = level; | ||
| 1854 | return level; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | DEFUN ("treesit-parser-parent-node", | ||
| 1858 | Ftreesit_parser_parent_node, Streesit_parser_parent_node, | ||
| 1859 | 1, 1, 0, | ||
| 1860 | doc: /* Return PARSER's parent node, if one exists. | ||
| 1861 | |||
| 1862 | Only embeded local parser can have parent node. When Emacs uses a node | ||
| 1863 | in the host parser to create this local parser, that node is considered | ||
| 1864 | the parent node of the local parser. */) | ||
| 1865 | (Lisp_Object parser) | ||
| 1866 | { | ||
| 1867 | treesit_check_parser (parser); | ||
| 1868 | return XTS_PARSER (parser)->parent_node; | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | DEFUN ("treesit-parser-set-parent-node", | ||
| 1872 | Ftreesit_parser_set_parent_node, Streesit_parser_set_parent_node, | ||
| 1873 | 2, 2, 0, | ||
| 1874 | doc: /* Return PARSER's parent node to NODE. */) | ||
| 1875 | (Lisp_Object parser, Lisp_Object node) | ||
| 1876 | { | ||
| 1877 | treesit_check_parser (parser); | ||
| 1878 | if (!NILP (node)) | ||
| 1879 | CHECK_TS_NODE (node); | ||
| 1880 | |||
| 1881 | XTS_PARSER (parser)->parent_node = node; | ||
| 1882 | return node; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | |||
| 1821 | /* Return true if PARSER is not deleted and its buffer is live. */ | 1886 | /* Return true if PARSER is not deleted and its buffer is live. */ |
| 1822 | static bool | 1887 | static bool |
| 1823 | treesit_parser_live_p (Lisp_Object parser) | 1888 | treesit_parser_live_p (Lisp_Object parser) |
| @@ -4538,6 +4603,10 @@ applies to LANGUAGE-A will be redirected to LANGUAGE-B instead. */); | |||
| 4538 | defsubr (&Streesit_parser_buffer); | 4603 | defsubr (&Streesit_parser_buffer); |
| 4539 | defsubr (&Streesit_parser_language); | 4604 | defsubr (&Streesit_parser_language); |
| 4540 | defsubr (&Streesit_parser_tag); | 4605 | defsubr (&Streesit_parser_tag); |
| 4606 | defsubr (&Streesit_parser_embed_level); | ||
| 4607 | defsubr (&Streesit_parser_set_embed_level); | ||
| 4608 | defsubr (&Streesit_parser_parent_node); | ||
| 4609 | defsubr (&Streesit_parser_set_parent_node); | ||
| 4541 | 4610 | ||
| 4542 | defsubr (&Streesit_parser_root_node); | 4611 | defsubr (&Streesit_parser_root_node); |
| 4543 | defsubr (&Streesit_parse_string); | 4612 | defsubr (&Streesit_parse_string); |
diff --git a/src/treesit.h b/src/treesit.h index 19dc28af246..d19a0e76216 100644 --- a/src/treesit.h +++ b/src/treesit.h | |||
| @@ -63,6 +63,28 @@ struct Lisp_TS_Parser | |||
| 63 | but rather return DEFAULT_RANGE. (A single range where start_byte | 63 | but rather return DEFAULT_RANGE. (A single range where start_byte |
| 64 | = 0, end_byte = UINT32_MAX). */ | 64 | = 0, end_byte = UINT32_MAX). */ |
| 65 | Lisp_Object last_set_ranges; | 65 | Lisp_Object last_set_ranges; |
| 66 | /* Parsers for embedded code blocks will have a non-zero embed level. | ||
| 67 | The primary parser has level 0, and each layer of embedded parser | ||
| 68 | gets +1 level. The embed level can be either a non-negative | ||
| 69 | integer or nil. Every parser created by treesit-parser-create | ||
| 70 | starts with a nil level. If the value is nil, that means the range | ||
| 71 | functions (treesit-update-ranges and friends) haven't touched this | ||
| 72 | parser yet, and this parser isn't part of the embed parser tree. */ | ||
| 73 | Lisp_Object embed_level; | ||
| 74 | /* Some comments: Technically you could calculate embed_level by | ||
| 75 | following parent_node, but parent_node might be outdated so it's a | ||
| 76 | good idea to record embed_level separately. Embed_level and | ||
| 77 | parent_node could have been implemented as "parser properties" with | ||
| 78 | an obarray, but ultimately I think two explicit fields helps | ||
| 79 | documentation better and it's not clear to me that a property list | ||
| 80 | for a parser will be useful beyond this. And we can always convert | ||
| 81 | these to properties later, but not vice versa. */ | ||
| 82 | /* When an embedded parser is created, it's usually based on a node in | ||
| 83 | the host parser. This field saves that node so it possible to | ||
| 84 | climb up and out of the embedded parser into the host parser. Note | ||
| 85 | that the range of the embedded parser doesn't have to match that of | ||
| 86 | the parent node. */ | ||
| 87 | Lisp_Object parent_node; | ||
| 66 | /* The buffer associated with this parser. */ | 88 | /* The buffer associated with this parser. */ |
| 67 | Lisp_Object buffer; | 89 | Lisp_Object buffer; |
| 68 | /* The pointer to the tree-sitter parser. Never NULL. */ | 90 | /* The pointer to the tree-sitter parser. Never NULL. */ |