esc
Externally Scriptable Editor
git clone git://mccd.space/esc
| Log | Files | Refs | README |
treesitter.c (2269B)
1 #ifdef HAVE_TREESITTER
2 #include "treesitter.h"
3 #include <tree_sitter/api.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #ifdef HAVE_TS_C
8 extern const TSLanguage *tree_sitter_c(void);
9 #endif
10 #ifdef HAVE_TS_MARKDOWN
11 extern const TSLanguage *tree_sitter_markdown(void);
12 #endif
13
14 struct TsState {
15 TSParser *parser;
16 TSTree *tree;
17 };
18
19 static const TSLanguage *detect_language(const char *filename) {
20 if (!filename) return NULL;
21 const char *ext = strrchr(filename, '.');
22 if (!ext) return NULL;
23 ext++;
24 #ifdef HAVE_TS_C
25 if (strcmp(ext, "c") == 0 || strcmp(ext, "h") == 0)
26 return tree_sitter_c();
27 #endif
28 #ifdef HAVE_TS_MARKDOWN
29 if (strcmp(ext, "md") == 0 || strcmp(ext, "markdown") == 0)
30 return tree_sitter_markdown();
31 #endif
32 return NULL;
33 }
34
35 TsState *ts_state_create(const char *filename) {
36 const TSLanguage *lang = detect_language(filename);
37 if (!lang) return NULL;
38 TsState *s = malloc(sizeof *s);
39 s->parser = ts_parser_new();
40 ts_parser_set_language(s->parser, lang);
41 s->tree = NULL;
42 return s;
43 }
44
45 void ts_state_destroy(TsState *s) {
46 if (!s) return;
47 if (s->tree) ts_tree_delete(s->tree);
48 ts_parser_delete(s->parser);
49 free(s);
50 }
51
52 void ts_state_parse(TsState *s, const char *text, size_t len) {
53 TSTree *new_tree = ts_parser_parse_string(s->parser, s->tree,
54 text, (uint32_t)len);
55 if (s->tree) ts_tree_delete(s->tree);
56 s->tree = new_tree;
57 }
58
59 bool ts_state_expand(TsState *s, int sel_start, int sel_end,
60 int *out_start, int *out_end) {
61 if (!s || !s->tree) return false;
62 TSNode root = ts_tree_root_node(s->tree);
63 uint32_t a = (uint32_t)sel_start;
64 uint32_t b = sel_end > sel_start ? (uint32_t)(sel_end - 1) : a;
65 TSNode node = ts_node_descendant_for_byte_range(root, a, b);
66 uint32_t ns = ts_node_start_byte(node);
67 uint32_t ne = ts_node_end_byte(node);
68 /* If tightest node == current selection, climb to parent */
69 while ((int)ns == sel_start && (int)ne == sel_end) {
70 TSNode parent = ts_node_parent(node);
71 if (ts_node_is_null(parent)) return false;
72 node = parent;
73 ns = ts_node_start_byte(node);
74 ne = ts_node_end_byte(node);
75 }
76 if ((int)ns == sel_start && (int)ne == sel_end) return false;
77 *out_start = (int)ns;
78 *out_end = (int)ne;
79 return true;
80 }
81 #endif /* HAVE_TREESITTER */