emacs-31 29bbd02347d: Fix treesit_cursor_helper_1 for zero-width nodes (bug#81436)

Yuan Fu <[email protected]> Fri, 24 Jul 2026 04:41:32 -0400 (EDT)
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: emacs-31
commit 29bbd02347da44599cc9778d9d626fc5c8ca4b2e
Author: Yuan Fu <[email protected]>
Commit: Yuan Fu <[email protected]>

    Fix treesit_cursor_helper_1 for zero-width nodes (bug#81436)
    
    * lisp/treesit.el (treesit--some): Add edebug declare.
    * src/treesit.c (treesit_cursor_helper_1): Don't use
    ts_tree_cursor_goto_first_child_for_byte for zero-width nodes.
---
 lisp/treesit.el |  2 +-
 src/treesit.c   | 10 +++++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/lisp/treesit.el b/lisp/treesit.el
index 5cef42ef454..7fa7df08194 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -3810,7 +3810,7 @@ the current line if the beginning of the defun is indented."
 Return the first non-nil evaluation of BODY.
 
 \(fn (SYM VAL) &rest BODY)"
-  (declare (indent 1))
+  (declare (indent 1) (debug ((symbolp form) body)))
   (let ((result-sym (gensym))
         (val-sym (gensym))
         (sym (car sym-val))
diff --git a/src/treesit.c b/src/treesit.c
index 7fb11048d18..84103473387 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -4259,9 +4259,13 @@ treesit_cursor_helper_1 (TSTreeCursor *cursor, TSNode *target,
     return true;
 
   /* ts_tree_cursor_goto_first_child_for_byte is significantly faster,
-     so despite it having problems (see bug#60127), we try it
-     first.  */
-  if (ts_tree_cursor_goto_first_child_for_byte (cursor, start_pos) == -1
+     so despite it having problems (see bug#60127), we try it first.
+     Also, ts_tree_cursor_goto_first_child_for_byte can't find
+     zero-width nodes (which exists and are legit, e.g., markdown's
+     block_continuation), because a zero-width node can't contain a pos
+     (end > pos).  */
+  if (start_pos != end_pos
+      && ts_tree_cursor_goto_first_child_for_byte (cursor, start_pos) == -1
       && !ts_tree_cursor_goto_first_child (cursor))
     return false;