Skip to content

Commit 722862b

Browse files
feat(node): add child_containing_descendant
1 parent 9e3806b commit 722862b

File tree

3 files changed

+29
-2
lines changed

3 files changed

+29
-2
lines changed

docs/classes/tree_sitter.Node.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Node
99
.. automethod:: child
1010
.. automethod:: child_by_field_id
1111
.. automethod:: child_by_field_name
12+
.. automethod:: child_containing_descendant
13+
14+
.. versionadded:: 0.23.0
1215
.. automethod:: children_by_field_id
1316
.. automethod:: children_by_field_name
1417
.. automethod:: descendant_for_byte_range

tree_sitter/__init__.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ class Node:
119119
def named_child(self, index: int, /) -> Node | None: ...
120120
def child_by_field_id(self, id: int, /) -> Node | None: ...
121121
def child_by_field_name(self, name: str, /) -> Node | None: ...
122+
def child_containing_descendant(self, descendant: Node, /) -> Node | None: ...
122123
def children_by_field_id(self, id: int, /) -> list[Node]: ...
123124
def children_by_field_name(self, name: str, /) -> list[Node]: ...
124125
def field_name_for_child(self, child_index: int, /) -> str | None: ...

tree_sitter/binding/node.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,20 @@ PyObject *node_named_descendant_for_point_range(Node *self, PyObject *args) {
279279
return node_new_internal(state, descendant, self->tree);
280280
}
281281

282+
PyObject *node_child_containing_descendant(Node *self, PyObject *args) {
283+
ModuleState *state = GET_MODULE_STATE(self);
284+
TSNode descendant;
285+
if (!PyArg_ParseTuple(args, "O!:child_containing_descendant", &descendant, state->node_type)) {
286+
return NULL;
287+
}
288+
289+
TSNode child = ts_node_child_containing_descendant(self->node, descendant);
290+
if (ts_node_is_null(child)) {
291+
Py_RETURN_NONE;
292+
}
293+
return node_new_internal(state, child, self->tree);
294+
}
295+
282296
PyObject *node_get_id(Node *self, void *Py_UNUSED(payload)) {
283297
return PyLong_FromVoidPtr((void *)self->node.id);
284298
}
@@ -578,7 +592,7 @@ PyDoc_STRVAR(node_child_by_field_id_doc,
578592
PyDoc_STRVAR(node_children_by_field_id_doc,
579593
"children_by_field_id(self, id, /)\n--\n\n"
580594
"Get a list of children with the given numerical field id."
581-
DOC_SEE_ALSO ":meth:`children_by_field_name`" );
595+
DOC_SEE_ALSO ":meth:`children_by_field_name`");
582596
PyDoc_STRVAR(node_child_by_field_name_doc, "child_by_field_name(self, name, /)\n--\n\n"
583597
"Get the first child with the given field name.");
584598
PyDoc_STRVAR(node_children_by_field_name_doc, "children_by_field_name(self, name, /)\n--\n\n"
@@ -598,6 +612,9 @@ PyDoc_STRVAR(node_descendant_for_point_range_doc,
598612
PyDoc_STRVAR(node_named_descendant_for_point_range_doc,
599613
"named_descendant_for_point_range(self, start_point, end_point, /)\n--\n\n"
600614
"Get the smallest *named* node within this node that spans the given point range.");
615+
PyDoc_STRVAR(node_child_containing_descendant_doc,
616+
"child_containing_descendant(self, descendant, /)\n--\n\n"
617+
"Get the child of the node that contains the given descendant.");
601618

602619
static PyMethodDef node_methods[] = {
603620
{
@@ -678,6 +695,12 @@ static PyMethodDef node_methods[] = {
678695
.ml_flags = METH_VARARGS,
679696
.ml_doc = node_named_descendant_for_point_range_doc,
680697
},
698+
{
699+
.ml_name = "child_containing_descendant",
700+
.ml_meth = (PyCFunction)node_child_containing_descendant,
701+
.ml_flags = METH_VARARGS,
702+
.ml_doc = node_child_containing_descendant_doc,
703+
},
681704
{NULL},
682705
};
683706

@@ -702,7 +725,7 @@ static PyGetSetDef node_accessors[] = {
702725
NULL},
703726
{"is_extra", (getter)node_get_is_extra, NULL,
704727
PyDoc_STR("Check if this node is _extra_.\n\nExtra nodes represent things which are not "
705-
"required the grammar but can appear anywhere (e.g. whitespace)."),
728+
"required by the grammar but can appear anywhere (e.g. whitespace)."),
706729
NULL},
707730
{"has_changes", (getter)node_get_has_changes, NULL,
708731
PyDoc_STR("Check if this node has been edited."), NULL},

0 commit comments

Comments
 (0)