Add treesit_assume_true and treesit_cursor_helper
This is part 1 of the change to change node API to cursor API. See the second part for more detail. (I splitted the change to make the diff more sane.) * src/treesit.c (treesit_assume_true) (treesit_cursor_helper): New functions.
This commit is contained in:
parent
a54c7a8df0
commit
a275e436df
1 changed files with 67 additions and 0 deletions
|
@ -2620,6 +2620,73 @@ the query. */)
|
||||||
|
|
||||||
/*** Navigation */
|
/*** Navigation */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
treesit_assume_true (bool val)
|
||||||
|
{
|
||||||
|
eassert (val == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a TSTreeCursor pointing at NODE. PARSER is the lisp parser
|
||||||
|
that produced NODE.
|
||||||
|
|
||||||
|
The reason we need this instead of simply using ts_tree_cursor_new
|
||||||
|
is that we have to create the cursor on the root node and traverse
|
||||||
|
down to NODE, in order to record the correct stack of parent nodes.
|
||||||
|
Otherwise going to sibling or parent of NODE wouldn't work.
|
||||||
|
|
||||||
|
(Wow perfect filling.) */
|
||||||
|
static TSTreeCursor
|
||||||
|
treesit_cursor_helper (TSNode node, Lisp_Object parser)
|
||||||
|
{
|
||||||
|
uint32_t end_pos = ts_node_end_byte (node);
|
||||||
|
TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree);
|
||||||
|
TSTreeCursor cursor = ts_tree_cursor_new (root);
|
||||||
|
TSNode cursor_node = ts_tree_cursor_current_node (&cursor);
|
||||||
|
/* This is like treesit-node-at. We go down from the root node,
|
||||||
|
either to first child or next sibling, repeatedly, and finally
|
||||||
|
arrive at NODE. */
|
||||||
|
while (!ts_node_eq (node, cursor_node))
|
||||||
|
{
|
||||||
|
treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor));
|
||||||
|
cursor_node = ts_tree_cursor_current_node (&cursor);
|
||||||
|
/* ts_tree_cursor_goto_first_child_for_byte is not reliable, so
|
||||||
|
we just go through each sibling. */
|
||||||
|
while (ts_node_is_missing (cursor_node)
|
||||||
|
|| ts_node_end_byte (cursor_node) < end_pos)
|
||||||
|
{
|
||||||
|
/* A "missing" node has zero width, so it's possible that
|
||||||
|
its end = NODE.end but it's not NODE, so we skip them.
|
||||||
|
But we need to make sure this missing node is not the
|
||||||
|
node we are looking for before skipping it. */
|
||||||
|
if (ts_node_is_missing (cursor_node)
|
||||||
|
&& ts_node_eq (node, cursor_node))
|
||||||
|
return cursor;
|
||||||
|
treesit_assume_true (ts_tree_cursor_goto_next_sibling (&cursor));
|
||||||
|
cursor_node = ts_tree_cursor_current_node (&cursor);
|
||||||
|
}
|
||||||
|
/* Right now CURSOR.end >= NODE.end. But what if CURSOR.end =
|
||||||
|
NODE.end, and there are missing nodes after CURSOR, and the
|
||||||
|
missing node after CURSOR is the NODE we are looking for??
|
||||||
|
Well, create a probe and look ahead. (This is tested by
|
||||||
|
treesit-cursor-helper-with-missing-node.) */
|
||||||
|
TSTreeCursor probe = ts_tree_cursor_copy (&cursor);
|
||||||
|
TSNode probe_node;
|
||||||
|
while (ts_tree_cursor_goto_next_sibling (&probe))
|
||||||
|
{
|
||||||
|
probe_node = ts_tree_cursor_current_node (&probe);
|
||||||
|
if (!ts_node_is_missing (probe_node))
|
||||||
|
break;
|
||||||
|
if (ts_node_eq (probe_node, node))
|
||||||
|
{
|
||||||
|
ts_tree_cursor_delete (&cursor);
|
||||||
|
return probe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ts_tree_cursor_delete (&probe);
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the next/previous named/unnamed sibling of NODE. FORWARD
|
/* Return the next/previous named/unnamed sibling of NODE. FORWARD
|
||||||
controls the direction and NAMED controls the nameness. */
|
controls the direction and NAMED controls the nameness. */
|
||||||
static TSNode
|
static TSNode
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue