summaryrefslogtreecommitdiff
path: root/src/treesit.c
diff options
context:
space:
mode:
authorYuan Fu <casouri@gmail.com>2023-01-17 00:57:54 -0800
committerYuan Fu <casouri@gmail.com>2023-01-17 01:18:16 -0800
commit7c61a304104fe3a35c47d412150d29b93a697c5e (patch)
tree1296bb007bf5d3ed5a6364f2fe0d8d6f6353c6b2 /src/treesit.c
parentb36cc7e7bbb5a8d0c1b298b89a4cb562af746ecc (diff)
downloademacs-7c61a304104fe3a35c47d412150d29b93a697c5e.tar.gz
emacs-7c61a304104fe3a35c47d412150d29b93a697c5e.tar.bz2
emacs-7c61a304104fe3a35c47d412150d29b93a697c5e.zip
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.
Diffstat (limited to 'src/treesit.c')
-rw-r--r--src/treesit.c52
1 files 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);
}