]> git.eshelyaron.com Git - emacs.git/commitdiff
Make treesit-node-child and fiends accept negative index
authorYuan Fu <casouri@gmail.com>
Mon, 24 Oct 2022 01:05:10 +0000 (18:05 -0700)
committerYuan Fu <casouri@gmail.com>
Mon, 24 Oct 2022 01:05:10 +0000 (18:05 -0700)
* doc/lispref/parsing.texi (Retrieving Node): Update manual.
* src/treesit.c (Ftreesit_node_child)
(Ftreesit_node_field_name_for_child): Accept and process negative
index.

doc/lispref/parsing.texi
src/treesit.c

index e26090be1d73b9509a73045ac5085ba51313ca09..3a19b1b7caafadf9de169a692bb29a4f35317d28 100644 (file)
@@ -567,11 +567,16 @@ This function returns the immediate parent of @var{node}.
 @defun treesit-node-child node n &optional named
 This function returns the @var{n}'th child of @var{node}.  If
 @var{named} is non-@code{nil}, it counts only named nodes
-(@pxref{tree-sitter named node, named node}).  For example, in a node
-that represents a string @code{"text"}, there are three children
-nodes: the opening quote @code{"}, the string text @code{text}, and
-the closing quote @code{"}.  Among these nodes, the first child is the
-opening quote @code{"}, and the first named child is the string text.
+(@pxref{tree-sitter named node, named node}).
+
+For example, in a node that represents a string @code{"text"}, there
+are three children nodes: the opening quote @code{"}, the string text
+@code{text}, and the closing quote @code{"}.  Among these nodes, the
+first child is the opening quote @code{"}, and the first named child
+is the string text.
+
+This function returns @code{nil} if there is no @var{n}'th child.
+@var{n} could be negative, e.g., -1 represents the last child.
 @end defun
 
 @defun treesit-node-children node &optional named
@@ -880,7 +885,11 @@ of @var{node} as a child of its parent.
 
 @defun treesit-node-field-name-for-child node n
 This function returns the field name of the @var{n}'th child of
-@var{node}.
+@var{node}.  It returns @code{nil} if there is no @var{n}'th child, or
+the @var{n}'th child doesn't have a field name.
+
+Note that @var{n} counts both named and anonymous child.  And @var{n}
+could be negative, e.g., -1 represents the last child.
 @end defun
 
 @defun treesit-child-count node &optional named
index b0e7d0e211a60cf70eb555c48bb65113cc995330..3ac0a0c7b2ecf7253b92faad88ce99c06bfb8cde 100644 (file)
@@ -1529,20 +1529,36 @@ DEFUN ("treesit-node-child",
        Ftreesit_node_child, Streesit_node_child, 2, 3, 0,
        doc: /* Return the Nth child of NODE.
 
-Return nil if there is no Nth child.  If NAMED is non-nil, look for named
-child only.  NAMED defaults to nil.  If NODE is nil, return nil.  */)
+Return nil if there is no Nth child.  If NAMED is non-nil, look for
+named child only.  NAMED defaults to nil.  If NODE is nil, return
+nil.
+
+N could be negative, e.g., -1 represents the last child.  */)
   (Lisp_Object node, Lisp_Object n, Lisp_Object named)
 {
   if (NILP (node)) return Qnil;
   treesit_check_node (node);
-  treesit_check_positive_integer (n);
+  CHECK_INTEGER (n);
   EMACS_INT idx = XFIXNUM (n);
-  if (idx > UINT32_MAX)
-    xsignal1 (Qargs_out_of_range, n);
+
   treesit_initialize ();
 
   TSNode treesit_node = XTS_NODE (node)->node;
   TSNode child;
+
+  /* Process negative index.  */
+  if (idx < 0)
+    {
+      if (NILP (named))
+       idx = ts_node_child_count (treesit_node) + idx;
+      else
+       idx = ts_node_named_child_count (treesit_node) + idx;
+    }
+  if (idx < 0)
+    return Qnil;
+  if (idx > UINT32_MAX)
+    xsignal1 (Qargs_out_of_range, n);
+
   if (NILP (named))
     child = ts_node_child (treesit_node, (uint32_t) idx);
   else
@@ -1606,19 +1622,30 @@ DEFUN ("treesit-node-field-name-for-child",
        doc: /* Return the field name of the Nth child of NODE.
 
 Return nil if there's no Nth child, or if it has no field.
-If NODE is nil, return nil.  */)
+If NODE is nil, return nil.
+
+N counts all children, i.e., named ones and anonymous ones.
+
+N could be negative, e.g., -1 represents the last child.  */)
   (Lisp_Object node, Lisp_Object n)
 {
   if (NILP (node))
     return Qnil;
   treesit_check_node (node);
-  treesit_check_positive_integer (n);
+  CHECK_INTEGER (n);
   EMACS_INT idx = XFIXNUM (n);
-  if (idx > UINT32_MAX)
-    xsignal1 (Qargs_out_of_range, n);
   treesit_initialize ();
 
   TSNode treesit_node = XTS_NODE (node)->node;
+
+  /* Process negative index.  */
+  if (idx < 0)
+    idx = ts_node_child_count (treesit_node) + idx;
+  if (idx < 0)
+    return Qnil;
+  if (idx > UINT32_MAX)
+    xsignal1 (Qargs_out_of_range, n);
+
   const char *name
     = ts_node_field_name_for_child (treesit_node, (uint32_t) idx);