diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index 5749a7c6..3fed02ce 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -79,8 +79,10 @@ TSNode ts_node_next_sibling(TSNode); TSNode ts_node_next_named_sibling(TSNode); TSNode ts_node_prev_sibling(TSNode); TSNode ts_node_prev_named_sibling(TSNode); -TSNode ts_node_descendant_for_range(TSNode, size_t, size_t); -TSNode ts_node_named_descendant_for_range(TSNode, size_t, size_t); +TSNode ts_node_descendant_for_char_range(TSNode, size_t, size_t); +TSNode ts_node_named_descendant_for_char_range(TSNode, size_t, size_t); +TSNode ts_node_descendant_for_point_range(TSNode, TSPoint, TSPoint); +TSNode ts_node_named_descendant_for_point_range(TSNode, TSPoint, TSPoint); TSDocument *ts_document_new(); void ts_document_free(TSDocument *); diff --git a/spec/integration/corpus_specs.cc b/spec/integration/corpus_specs.cc index ed44c9cb..3653809d 100644 --- a/spec/integration/corpus_specs.cc +++ b/spec/integration/corpus_specs.cc @@ -80,7 +80,7 @@ describe("The Corpus", []() { document = ts_document_new(); ts_document_set_language(document, get_test_language(language_name)); - ts_document_set_logger(document, stderr_logger_new(true)); + // ts_document_set_logger(document, stderr_logger_new(true)); // ts_document_print_debugging_graphs(document, true); }); diff --git a/spec/runtime/node_spec.cc b/spec/runtime/node_spec.cc index 6c31fe5b..9c7e0e39 100644 --- a/spec/runtime/node_spec.cc +++ b/spec/runtime/node_spec.cc @@ -11,7 +11,8 @@ START_TEST describe("Node", []() { TSDocument *document; TSNode array_node; - string input_string = "\n" + string input_string = + "\n" "\n" "[\n" " 123,\n" @@ -148,7 +149,7 @@ describe("Node", []() { ts_symbol_iterator_next(&iterator); AssertThat(iterator.done, Equals(true)); - TSNode false_node = ts_node_descendant_for_range(array_node, false_index, false_index + 1); + TSNode false_node = ts_node_descendant_for_char_range(array_node, false_index, false_index + 1); iterator = ts_node_symbols(false_node); AssertThat(iterator.done, Equals(false)); AssertThat(ts_language_symbol_name(language, iterator.value), Equals("false")); @@ -160,7 +161,7 @@ describe("Node", []() { ts_symbol_iterator_next(&iterator); AssertThat(iterator.done, Equals(true)); - TSNode comma_node = ts_node_descendant_for_range(array_node, number_end_index, number_end_index); + TSNode comma_node = ts_node_descendant_for_char_range(array_node, number_end_index, number_end_index); iterator = ts_node_symbols(comma_node); AssertThat(iterator.done, Equals(false)); AssertThat(ts_language_symbol_name(language, iterator.value), Equals(",")); @@ -332,17 +333,17 @@ describe("Node", []() { }); }); - describe("named_descendant_for_range(start, end)", [&]() { + describe("named_descendant_for_char_range(start, end)", [&]() { describe("when there is a leaf node that spans the given range exactly", [&]() { it("returns that leaf node", [&]() { - TSNode leaf = ts_node_named_descendant_for_range(array_node, string_index, string_end_index - 1); + TSNode leaf = ts_node_named_descendant_for_char_range(array_node, string_index, string_end_index - 1); AssertThat(ts_node_name(leaf, document), Equals("string")); AssertThat(ts_node_start_byte(leaf), Equals(string_index)); AssertThat(ts_node_end_byte(leaf), Equals(string_end_index)); AssertThat(ts_node_start_point(leaf), Equals({ 6, 4 })); AssertThat(ts_node_end_point(leaf), Equals({ 6, 7 })); - leaf = ts_node_named_descendant_for_range(array_node, number_index, number_end_index - 1); + leaf = ts_node_named_descendant_for_char_range(array_node, number_index, number_end_index - 1); AssertThat(ts_node_name(leaf, document), Equals("number")); AssertThat(ts_node_start_byte(leaf), Equals(number_index)); AssertThat(ts_node_end_byte(leaf), Equals(number_end_index)); @@ -353,14 +354,14 @@ describe("Node", []() { describe("when there is a leaf node that extends beyond the given range", [&]() { it("returns that leaf node", [&]() { - TSNode leaf = ts_node_named_descendant_for_range(array_node, string_index, string_index + 1); + TSNode leaf = ts_node_named_descendant_for_char_range(array_node, string_index, string_index + 1); AssertThat(ts_node_name(leaf, document), Equals("string")); AssertThat(ts_node_start_byte(leaf), Equals(string_index)); AssertThat(ts_node_end_byte(leaf), Equals(string_end_index)); AssertThat(ts_node_start_point(leaf), Equals({ 6, 4 })); AssertThat(ts_node_end_point(leaf), Equals({ 6, 7 })); - leaf = ts_node_named_descendant_for_range(array_node, string_index + 1, string_index + 2); + leaf = ts_node_named_descendant_for_char_range(array_node, string_index + 1, string_index + 2); AssertThat(ts_node_name(leaf, document), Equals("string")); AssertThat(ts_node_start_byte(leaf), Equals(string_index)); AssertThat(ts_node_end_byte(leaf), Equals(string_end_index)); @@ -371,7 +372,7 @@ describe("Node", []() { describe("when there is no leaf node that spans the given range", [&]() { it("returns the smallest node that does span the range", [&]() { - TSNode pair_node = ts_node_named_descendant_for_range(array_node, string_index, string_index + 3); + TSNode pair_node = ts_node_named_descendant_for_char_range(array_node, string_index, string_index + 3); AssertThat(ts_node_name(pair_node, document), Equals("pair")); AssertThat(ts_node_start_byte(pair_node), Equals(string_index)); AssertThat(ts_node_end_byte(pair_node), Equals(null_end_index)); @@ -380,7 +381,7 @@ describe("Node", []() { }); it("does not return invisible nodes (repeats)", [&]() { - TSNode node = ts_node_named_descendant_for_range(array_node, number_end_index, number_end_index + 1); + TSNode node = ts_node_named_descendant_for_char_range(array_node, number_end_index, number_end_index + 1); AssertThat(ts_node_name(node, document), Equals("array")); AssertThat(ts_node_start_byte(node), Equals(array_index)); AssertThat(ts_node_end_byte(node), Equals(array_end_index)); @@ -390,16 +391,34 @@ describe("Node", []() { }); }); - describe("descendant_for_range(start, end)", [&]() { + describe("descendant_for_char_range(start, end)", [&]() { it("returns the smallest concrete node that spans the given range", [&]() { - TSNode node1 = ts_node_descendant_for_range(array_node, colon_index, colon_index); + TSNode node1 = ts_node_descendant_for_char_range(array_node, colon_index, colon_index); AssertThat(ts_node_name(node1, document), Equals(":")); AssertThat(ts_node_start_byte(node1), Equals(colon_index)); AssertThat(ts_node_end_byte(node1), Equals(colon_index + 1)); AssertThat(ts_node_start_point(node1), Equals({ 6, 7 })); AssertThat(ts_node_end_point(node1), Equals({ 6, 8 })); - TSNode node2 = ts_node_descendant_for_range(array_node, string_index + 2, string_index + 4); + TSNode node2 = ts_node_descendant_for_char_range(array_node, string_index + 2, string_index + 4); + AssertThat(ts_node_name(node2, document), Equals("pair")); + AssertThat(ts_node_start_byte(node2), Equals(string_index)); + AssertThat(ts_node_end_byte(node2), Equals(null_end_index)); + AssertThat(ts_node_start_point(node2), Equals({ 6, 4 })); + AssertThat(ts_node_end_point(node2), Equals({ 6, 13 })); + }); + }); + + describe("named_descendant_for_point_range(start, end)", [&]() { + it("returns the smallest concrete node that spans the given range", [&]() { + TSNode node1 = ts_node_descendant_for_point_range(array_node, {6, 7}, {6, 7}); + AssertThat(ts_node_name(node1, document), Equals(":")); + AssertThat(ts_node_start_byte(node1), Equals(colon_index)); + AssertThat(ts_node_end_byte(node1), Equals(colon_index + 1)); + AssertThat(ts_node_start_point(node1), Equals({ 6, 7 })); + AssertThat(ts_node_end_point(node1), Equals({ 6, 8 })); + + TSNode node2 = ts_node_descendant_for_point_range(array_node, {6, 6}, {6, 8}); AssertThat(ts_node_name(node2, document), Equals("pair")); AssertThat(ts_node_start_byte(node2), Equals(string_index)); AssertThat(ts_node_end_byte(node2), Equals(null_end_index)); diff --git a/spec/runtime/parser_spec.cc b/spec/runtime/parser_spec.cc index db4b5f74..5595e6c8 100644 --- a/spec/runtime/parser_spec.cc +++ b/spec/runtime/parser_spec.cc @@ -308,7 +308,7 @@ describe("Parser", [&]() { assert_root_node( "(program (expression_statement (math_op (identifier) (number))))"); - TSNode node = ts_node_named_descendant_for_range(root, 1, 1); + TSNode node = ts_node_named_descendant_for_char_range(root, 1, 1); AssertThat(ts_node_name(node, doc), Equals("identifier")); AssertThat(ts_node_end_byte(node), Equals(strlen("abXYZc"))); }); @@ -326,7 +326,7 @@ describe("Parser", [&]() { assert_root_node( "(program (expression_statement (math_op (identifier) (number))))"); - TSNode node = ts_node_named_descendant_for_range(root, 1, 1); + TSNode node = ts_node_named_descendant_for_char_range(root, 1, 1); AssertThat(ts_node_name(node, doc), Equals("identifier")); AssertThat(ts_node_end_byte(node), Equals(strlen("abcXYZ"))); }); diff --git a/src/runtime/node.c b/src/runtime/node.c index ad3264d8..5fed59dd 100644 --- a/src/runtime/node.c +++ b/src/runtime/node.c @@ -138,9 +138,13 @@ static inline TSNode ts_node__next_sibling(TSNode self, bool include_anonymous) return ts_node__null(); } -static inline TSNode ts_node__descendant_for_range(TSNode self, size_t min, - size_t max, - bool include_anonymous) { +static inline bool ts_point_gt(TSPoint a, TSPoint b) { + return a.row > b.row || (a.row == b.row && a.column > b.column); +} + +static inline TSNode ts_node__descendant_for_char_range(TSNode self, size_t min, + size_t max, + bool include_anonymous) { TSNode node = self; TSNode last_visible_node = self; @@ -165,6 +169,34 @@ static inline TSNode ts_node__descendant_for_range(TSNode self, size_t min, return last_visible_node; } +static inline TSNode ts_node__descendant_for_point_range(TSNode self, + TSPoint min, + TSPoint max, + bool include_anonymous) { + TSNode node = self; + TSNode last_visible_node = self; + + bool did_descend = true; + while (did_descend) { + did_descend = false; + + for (size_t i = 0; i < ts_node__tree(node)->child_count; i++) { + TSNode child = ts_node__direct_child(node, i); + if (ts_point_gt(ts_node_start_point(child), min)) + break; + if (ts_point_gt(ts_node_end_point(child), max)) { + node = child; + if (ts_node__is_relevant(node, include_anonymous)) + last_visible_node = node; + did_descend = true; + break; + } + } + } + + return last_visible_node; +} + /* * Public */ @@ -290,10 +322,18 @@ TSNode ts_node_prev_named_sibling(TSNode self) { return ts_node__prev_sibling(self, false); } -TSNode ts_node_descendant_for_range(TSNode self, size_t min, size_t max) { - return ts_node__descendant_for_range(self, min, max, true); +TSNode ts_node_descendant_for_char_range(TSNode self, size_t min, size_t max) { + return ts_node__descendant_for_char_range(self, min, max, true); } -TSNode ts_node_named_descendant_for_range(TSNode self, size_t min, size_t max) { - return ts_node__descendant_for_range(self, min, max, false); +TSNode ts_node_named_descendant_for_char_range(TSNode self, size_t min, size_t max) { + return ts_node__descendant_for_char_range(self, min, max, false); +} + +TSNode ts_node_descendant_for_point_range(TSNode self, TSPoint min, TSPoint max) { + return ts_node__descendant_for_point_range(self, min, max, true); +} + +TSNode ts_node_named_descendant_for_point_range(TSNode self, TSPoint min, TSPoint max) { + return ts_node__descendant_for_point_range(self, min, max, false); }