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

From: Denis Zubarev <[email-masked]>
Date: Tue, 19 Dec 2023 20:08:04 +0300

I replaced treesit--thing-at with the function from emacs 29.1 in the last version of the patch.

Attached it here.

19.12.2023, 19:53, "Eli Zaretskii" <[email-masked]>:

From: Yuan Fu <[email-masked]>
Date: Mon, 18 Dec 2023 18:26:30 -0800
Cc: Eli Zaretskii <[email-masked]>,
[email-masked]

> On Dec 18, 2023, at 4:24 PM, Denis Zubarev <[email-masked]> wrote:
>
> Just FYI, my paperwork is done.
>

Great, applied! Closing this bug.

The new tests fail here:

ELC src/treesit-tests.elc

In end of data:
src/treesit-tests.el:1094:17: Warning: the function `treesit--thing-at' is not known to be defined.
[...]
Test treesit-search-subtree-backward-1 backtrace:
(treesit--thing-at (point) "call")
(treesit-search-subtree (treesit--thing-at (point) "call") #'(lambda
(let ((node (treesit-search-subtree (treesit--thing-at (point) "call
(closure (t) nil (let* ((fn-621 #'treesit-language-available-p) (arg
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name treesit-search-subtree-backward-1 :do
ert-run-or-rerun-test(#s(ert--stats :selector ... :tests ... :test-m
ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil
ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp))))
ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco
eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n
command-line-1(("-L" ";." "-l" "ert" "-l" "src/treesit-tests.el" "--
command-line()
normal-top-level()
Test treesit-search-subtree-backward-1 condition:
(void-function treesit--thing-at)
FAILED 24/25 treesit-search-subtree-backward-1 (0.000000 sec) at src/treesit-tests.el:1100
Can't guess python-indent-offset, using defaults: 4
Test treesit-search-subtree-forward-1 backtrace:
(treesit--thing-at (point) "call")
(treesit-search-subtree (treesit--thing-at (point) "call") #'(lambda
(let ((node (treesit-search-subtree (treesit--thing-at (point) "call
(closure (t) nil (let* ((fn-609 #'treesit-language-available-p) (arg
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name treesit-search-subtree-forward-1 :doc
ert-run-or-rerun-test(#s(ert--stats :selector ... :tests ... :test-m
ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil
ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp))))
ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco
eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n
command-line-1(("-L" ";." "-l" "ert" "-l" "src/treesit-tests.el" "--
command-line()
normal-top-level()
Test treesit-search-subtree-forward-1 condition:
(void-function treesit--thing-at)
FAILED 25/25 treesit-search-subtree-forward-1 (0.015625 sec) at src/treesit-tests.el:1086

The function treesit--thing-at is only available on master.

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