Subject: Re: bug#67117: [PATCH] Tree-sitter: fix an issue when searching subtree backward

From: Denis Zubarev <[email-masked]>
Date: Sun, 19 Nov 2023 14:25:14 +0300

I replaced use of `treesit--thing-at` with `treesit-query-capture`, so it should be compatible with emacs-29

19.11.2023, 12:16, "Eli Zaretskii" <[email-masked]>:

From: Yuan Fu <[email-masked]>
Date: Sat, 18 Nov 2023 22:13:49 -0800
Cc: [email-masked],
[email-masked]

> On Nov 18, 2023, at 9:47 PM, Eli Zaretskii <[email-masked]> wrote:
>
>> From: Yuan Fu <[email-masked]>
>> Date: Sat, 18 Nov 2023 10:47:47 -0800
>> Cc: Denis Zubarev <[email-masked]>,
>> [email-masked]
>>
>>
>>>> Steps to reproduce the issue:
>>>> 1. emacs -Q
>>>> 2. M-x find-file /tmp/t.py
>>>> 3. paste to the buffer
>>>>
>>>> Temp(1, 2)
>>>>
>>>> 4. M-x python-ts-mode
>>>> 5. Call search-subtree with backward flag
>>>> M-x eval-expression (treesit-search-subtree
>>>> (treesit--thing-at (point) "call")
>>>> (lambda (n) (equal (treesit-node-type n ) "integer"))
>>>> t)
>>>> It should return the second int node (#<treesit-node integer in 9-10>), but it returns nil.
>>>
>>> Yuan, any comments to the patch and the issue in general?
>>
>> LGTM. Thanks Denis, and Eli :-)
>
> Should we install this on the emacs-29 branch or on master?

Emacs-29, I’d say, since it’s a bug fix.

I see that the added tests use treesit--thing-at, which is not
available on the emacs-29 branch. So either we install the tests on
master, or we replace treesit--thing-at in the tests with its body.
WDYT?

From 040a8ad75625ea4e4277fbce920f84a83e15190e Mon Sep 17 00:00:00 2001
From: Denis Zubarev <[email-masked]>
Date: Sun, 12 Nov 2023 01:42:42 +0300
Subject: [PATCH] Fix an issue when searching subtree backward

* src/treesit.c (treesit_traverse_child_helper):
Do not call treesit_traverse_sibling_helper when the named node is
required and the last child is the named node.
Otherwise treesit_traverse_sibling_helper will move cursor to the
previous sibling and last node will be skipped.
* test/src/treesit-tests.el (treesit-search-subtree-forward-1):
(treesit-search-subtree-backward-1):
Add tests
---
 src/treesit.c             |  4 ++--
 test/src/treesit-tests.el | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/src/treesit.c b/src/treesit.c
index 69b59fca11..4dcad751f4 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -3247,9 +3247,9 @@ treesit_traverse_child_helper (TSTreeCursor *cursor,
       /* First go to the last child.  */
       while (ts_tree_cursor_goto_next_sibling (cursor));
 
-      if (!named)
+      if (!named || (named && ts_node_is_named (ts_tree_cursor_current_node(cursor))))
 	return true;
-      /* Else named... */
+      /* Else named is required and last child is not named node */
       if (treesit_traverse_sibling_helper(cursor, false, true))
 	return true;
       else
diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el
index 791e902bd0..6c3b1eed98 100644
--- a/test/src/treesit-tests.el
+++ b/test/src/treesit-tests.el
@@ -1167,6 +1167,40 @@ treesit-defun-navigation-top-level
    treesit--ert-defun-navigation-top-level-master
    'top-level))
 
+(ert-deftest treesit-search-subtree-forward-1 ()
+  "Test search subtree forward."
+  (skip-unless (treesit-language-available-p 'python))
+  (require 'python)
+  (python-ts-mode)
+  (insert "Temp(1, 2)")
+  (goto-char (point-min))
+  (pcase-let* ((`((,_ . ,call-node)) (treesit-query-capture (treesit-buffer-root-node)
+                                                            '((call) @c)))
+               (node (treesit-search-subtree
+                      call-node
+                      (lambda (n) (equal (treesit-node-type n) "integer")))))
+
+    (should node)
+    (should (equal (treesit-node-text node) "1"))))
+
+(ert-deftest treesit-search-subtree-backward-1 ()
+  "Test search subtree with backward=t."
+  (skip-unless (treesit-language-available-p 'python))
+  (require 'python)
+  (python-ts-mode)
+  (insert "Temp(1, 2)")
+  (goto-char (point-min))
+  (pcase-let* ((`((,_ . ,call-node)) (treesit-query-capture (treesit-buffer-root-node)
+                                                            '((call) @c)))
+               (node (treesit-search-subtree
+                      call-node
+                      (lambda (n) (equal (treesit-node-type n) "integer"))
+                      t)))
+
+    (should node)
+    (should (equal (treesit-node-text node) "2"))))
+
+
 ;; TODO
 ;; - Functions in treesit.el
 ;; - treesit-load-name-override-list
-- 
2.34.1