esc

Externally Scriptable Editor

git clone git://mccd.space/esc

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 */