emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

emacs-29 a275e436df 1/4: Add treesit_assume_true and treesit_cursor_help


From: Yuan Fu
Subject: emacs-29 a275e436df 1/4: Add treesit_assume_true and treesit_cursor_helper
Date: Sat, 17 Dec 2022 18:34:06 -0500 (EST)

branch: emacs-29
commit a275e436df438806a5a4f8c57423085a7147eb0a
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>

    Add treesit_assume_true and treesit_cursor_helper
    
    This is part 1 of the change to change node API to cursor API.  See
    the second part for more detail.  (I splitted the change to make the
    diff more sane.)
    
    * src/treesit.c (treesit_assume_true)
    (treesit_cursor_helper): New functions.
---
 src/treesit.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/src/treesit.c b/src/treesit.c
index d361a3da93..f595ecf3df 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -2620,6 +2620,73 @@ the query.  */)
 
 /*** Navigation */
 
+static inline void
+treesit_assume_true (bool val)
+{
+  eassert (val == true);
+}
+
+/* Create a TSTreeCursor pointing at NODE.  PARSER is the lisp parser
+   that produced NODE.
+
+   The reason we need this instead of simply using ts_tree_cursor_new
+   is that we have to create the cursor on the root node and traverse
+   down to NODE, in order to record the correct stack of parent nodes.
+   Otherwise going to sibling or parent of NODE wouldn't work.
+
+   (Wow perfect filling.)  */
+static TSTreeCursor
+treesit_cursor_helper (TSNode node, Lisp_Object parser)
+{
+  uint32_t end_pos = ts_node_end_byte (node);
+  TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree);
+  TSTreeCursor cursor = ts_tree_cursor_new (root);
+  TSNode cursor_node = ts_tree_cursor_current_node (&cursor);
+  /* This is like treesit-node-at.  We go down from the root node,
+     either to first child or next sibling, repeatedly, and finally
+     arrive at NODE.  */
+  while (!ts_node_eq (node, cursor_node))
+    {
+      treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor));
+      cursor_node = ts_tree_cursor_current_node (&cursor);
+      /* ts_tree_cursor_goto_first_child_for_byte is not reliable, so
+        we just go through each sibling.  */
+      while (ts_node_is_missing (cursor_node)
+            || ts_node_end_byte (cursor_node) < end_pos)
+       {
+         /* A "missing" node has zero width, so it's possible that
+            its end = NODE.end but it's not NODE, so we skip them.
+            But we need to make sure this missing node is not the
+            node we are looking for before skipping it.  */
+         if (ts_node_is_missing (cursor_node)
+             && ts_node_eq (node, cursor_node))
+           return cursor;
+         treesit_assume_true (ts_tree_cursor_goto_next_sibling (&cursor));
+         cursor_node = ts_tree_cursor_current_node (&cursor);
+       }
+      /* Right now CURSOR.end >= NODE.end.  But what if CURSOR.end =
+        NODE.end, and there are missing nodes after CURSOR, and the
+        missing node after CURSOR is the NODE we are looking for??
+        Well, create a probe and look ahead.  (This is tested by
+        treesit-cursor-helper-with-missing-node.)  */
+      TSTreeCursor probe = ts_tree_cursor_copy (&cursor);
+      TSNode probe_node;
+      while (ts_tree_cursor_goto_next_sibling (&probe))
+       {
+         probe_node = ts_tree_cursor_current_node (&probe);
+         if (!ts_node_is_missing (probe_node))
+           break;
+         if (ts_node_eq (probe_node, node))
+           {
+             ts_tree_cursor_delete (&cursor);
+             return probe;
+           }
+       }
+      ts_tree_cursor_delete (&probe);
+    }
+  return cursor;
+}
+
 /* Return the next/previous named/unnamed sibling of NODE.  FORWARD
    controls the direction and NAMED controls the nameness.  */
 static TSNode



reply via email to

[Prev in Thread] Current Thread [Next in Thread]