From 7c61a304104fe3a35c47d412150d29b93a697c5e Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Tue, 17 Jan 2023 00:57:54 -0800 Subject: [PATCH] Fix treesit-node-first-child-for-pos (bug#60127) The problem is due to a bug in ts_node_first_child_for_pos, but tree-sitter is moving pretty slowly right now so I reimplemented a correct version of it in treesit.c. * src/treesit.c (treesit_cursor_first_child_for_byte): New function. (Ftreesit_node_first_child_for_pos): Use the new function. --- src/treesit.c | 52 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/treesit.c b/src/treesit.c index adbed1427be..644d323d5cb 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -2095,6 +2095,41 @@ return nil. */) return make_treesit_node (XTS_NODE (node)->parser, sibling); } +/* Our reimplementation of ts_node_first_child_for_byte. The current + implementation of that function has problems (see bug#60127), so + before it's fixed upstream, we use our own reimplementation of it. + Return true if there is a valid sibling, return false otherwise. + If the return value is false, the position of the cursor is + undefined. (We use cursor because technically we can't make a null + node for ourselves, also, using cursor is more convenient.) + + TODO: Remove this function once tree-sitter fixed the bug. */ +static bool treesit_cursor_first_child_for_byte +(TSTreeCursor *cursor, ptrdiff_t pos, bool named) +{ + if (!ts_tree_cursor_goto_first_child (cursor)) + return false; + + TSNode node = ts_tree_cursor_current_node (cursor); + while (ts_node_end_byte (node) <= pos) + { + if (ts_tree_cursor_goto_next_sibling (cursor)) + node = ts_tree_cursor_current_node (cursor); + else + /* Reached the end and still can't find a valid sibling. */ + return false; + } + while (named && (!ts_node_is_named (node))) + { + if (ts_tree_cursor_goto_next_sibling (cursor)) + node = ts_tree_cursor_current_node (cursor); + else + /* Reached the end and still can't find a named sibling. */ + return false; + } + return true; +} + DEFUN ("treesit-node-first-child-for-pos", Ftreesit_node_first_child_for_pos, Streesit_node_first_child_for_pos, 2, 3, 0, @@ -2119,16 +2154,17 @@ Note that this function returns an immediate child, not the smallest ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos)); TSNode treesit_node = XTS_NODE (node)->node; - TSNode child; - if (NILP (named)) - child = ts_node_first_child_for_byte (treesit_node, byte_pos - visible_beg); - else - child = ts_node_first_named_child_for_byte (treesit_node, - byte_pos - visible_beg); - if (ts_node_is_null (child)) - return Qnil; + TSTreeCursor cursor = ts_tree_cursor_new (treesit_node); + ptrdiff_t treesit_pos = byte_pos - visible_beg; + bool success; + success = treesit_cursor_first_child_for_byte (&cursor, treesit_pos, + !NILP (named)); + TSNode child = ts_tree_cursor_current_node (&cursor); + ts_tree_cursor_delete (&cursor); + if (!success) + return Qnil; return make_treesit_node (XTS_NODE (node)->parser, child); } -- 2.39.2