diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index 57b2f38f..061ddd64 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -29,15 +29,15 @@ typedef struct TSDocument TSDocument; size_t ts_node_pos(const TSNode *); size_t ts_node_size(const TSNode *); TSSymbol ts_node_sym(const TSNode *); -const char * ts_node_name(const TSNode *); TSNode * ts_node_child(TSNode *, size_t); TSNode * ts_node_leaf_at_pos(TSNode *, size_t); TSNode * ts_node_parent(TSNode *node); TSNode * ts_node_next_sibling(TSNode *node); TSNode * ts_node_prev_sibling(TSNode *node); +const char * ts_node_name(const TSNode *); +const char * ts_node_string(const TSNode *); void ts_node_retain(TSNode *node); void ts_node_release(TSNode *node); -const char * ts_node_string(const TSNode *); int ts_node_eq(const TSNode *, const TSNode *); TSDocument * ts_document_make(); @@ -47,7 +47,6 @@ void ts_document_set_input(TSDocument *doc, TSInput input); void ts_document_set_input_string(TSDocument *doc, const char *text); void ts_document_edit(TSDocument *doc, TSInputEdit edit); const char * ts_document_string(const TSDocument *doc); -TSNode * ts_document_get_node(const TSDocument *document, size_t position); TSNode * ts_document_root_node(const TSDocument *document); #define ts_builtin_sym_error 0 diff --git a/spec/runtime/node_spec.cc b/spec/runtime/node_spec.cc index a2e9ffe8..9dcd44cf 100644 --- a/spec/runtime/node_spec.cc +++ b/spec/runtime/node_spec.cc @@ -68,6 +68,30 @@ describe("Node", []() { ts_node_release(number2); ts_node_release(number3); }); + + describe("retrieving leaf nodes", [&]() { + it("can retrieve the leaf node at a given position", [&]() { + TSNode *number1 = ts_node_leaf_at_pos(root, 3); + TSNode *number2 = ts_node_leaf_at_pos(root, 7); + + AssertThat(ts_node_name(number1), Equals("number")); + AssertThat(ts_node_size(number1), Equals(2)); + + AssertThat(ts_node_name(number2), Equals("number")); + AssertThat(ts_node_size(number2), Equals(1)); + + ts_node_release(number1); + ts_node_release(number2); + }); + + it("returns higher-level nodes when no leaf is at the given position", [&]() { + TSNode *node = ts_node_leaf_at_pos(root, 6); + + AssertThat(ts_node_name(node), Equals("array")); + + ts_node_release(node); + }); + }); }); END_TEST diff --git a/src/runtime/document.c b/src/runtime/document.c index fd2ac71b..1591b70c 100644 --- a/src/runtime/document.c +++ b/src/runtime/document.c @@ -28,6 +28,8 @@ void ts_document_free(TSDocument *document) { } void ts_document_set_parser(TSDocument *document, TSParser *parser) { + if (document->parser) + ts_parser_free(document->parser); document->parser = parser; } @@ -95,7 +97,7 @@ void ts_document_set_input_string(TSDocument *document, const char *text) { } TSNode * ts_document_root_node(const TSDocument *document) { - return ts_node_make_root(document->tree, &document->parser->config); + return ts_node_make_root(document->tree, document->parser->config.symbol_names); } TSNode * ts_document_get_node(const TSDocument *document, size_t pos) { diff --git a/src/runtime/node.c b/src/runtime/node.c index c3561c2f..7de3a786 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -1,8 +1,7 @@ #include "runtime/node.h" -#include "tree_sitter/parser.h" #include "runtime/tree.h" -TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t start_position, TSParserConfig *config) { +TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t start_position, const char **names) { if (parent) ts_node_retain(parent); TSNode *result = malloc(sizeof(TSNode)); *result = (TSNode) { @@ -11,15 +10,15 @@ TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t s .index = index, .content = tree, .start_position = start_position, - .config = config + .names = names, }; return result; } -TSNode * ts_node_make_root(const TSTree *tree, TSParserConfig *config) { +TSNode * ts_node_make_root(const TSTree *tree, const char **names) { while (ts_tree_is_wrapper(tree)) tree = tree->children[0]; - return ts_node_make(tree, NULL, 0, 0, config); + return ts_node_make(tree, NULL, 0, 0, names); } void ts_node_retain(TSNode *node) { @@ -47,11 +46,11 @@ int ts_node_eq(const TSNode *left, const TSNode *right) { } const char * ts_node_name(const TSNode *node) { - return node->config->symbol_names[node->content->symbol]; + return node->names[node->content->symbol]; } const char * ts_node_string(const TSNode *node) { - return ts_tree_string(node->content, node->config->symbol_names); + return ts_tree_string(node->content, node->names); } TSNode * ts_node_parent(TSNode *child) { @@ -72,9 +71,25 @@ TSNode * ts_node_child(TSNode *parent, size_t index) { if (child_count <= index) return NULL; size_t position = parent->start_position + children[index].position; - return ts_node_make(children[index].tree, parent, index, position, parent->config); + return ts_node_make(children[index].tree, parent, index, position, parent->names); } -TSNode * ts_node_leaf_at_pos(TSNode *parent, size_t child_index) { - return NULL; +TSNode * ts_node_leaf_at_pos(TSNode *parent, size_t position) { + size_t child_count; + TSChildWithPosition *children = ts_tree_visible_children(parent->content, &child_count); + for (size_t i = 0; i < child_count; i++) { + TSChildWithPosition child = children[i]; + size_t child_left = child.position + child.tree->offset; + if (child_left > position) + break; + if (child_left + child.tree->size > position) { + TSNode *node = ts_node_make(child.tree, parent, i, child.position, parent->names); + TSNode *result = ts_node_leaf_at_pos(node, position); + ts_node_release(node); + return result; + } + } + + ts_node_retain(parent); + return parent; } diff --git a/src/runtime/node.h b/src/runtime/node.h index db2a08c2..d39e921a 100644 --- a/src/runtime/node.h +++ b/src/runtime/node.h @@ -2,6 +2,7 @@ #define RUNTIME_NODE_H_ #include "tree_sitter/parser.h" +#include "runtime/tree.h" struct TSNode { size_t ref_count; @@ -9,10 +10,10 @@ struct TSNode { size_t index; const TSTree *content; struct TSNode *parent; - TSParserConfig *config; + const char **names; }; -TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t start_position, TSParserConfig *config); -TSNode * ts_node_make_root(const TSTree *tree, TSParserConfig *config); +TSNode * ts_node_make(const TSTree *tree, TSNode *parent, size_t index, size_t start_position, const char **names); +TSNode * ts_node_make_root(const TSTree *tree, const char **names); #endif