]> git.eshelyaron.com Git - emacs.git/commitdiff
Add 'and', 'named', and 'anonymous' predicate for tree-sitter
authorYuan Fu <casouri@gmail.com>
Mon, 13 Jan 2025 07:41:47 +0000 (23:41 -0800)
committerEshel Yaron <me@eshelyaron.com>
Mon, 13 Jan 2025 12:12:05 +0000 (13:12 +0100)
* doc/lispref/parsing.texi (User-defined Things): Mention the
new predicate.
* src/treesit.c (treesit_traverse_validate_predicate): Recognize
named, anonymous, and and predicates.
(treesit_traverse_match_predicate): Handle named, anonymous, and
and predicates.

(cherry picked from commit f0e63558bd3dfd9e57cacfba8690f9dd29774947)

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

index e16aea6a38ddc809d1efc0e5e839df3ad13a5e48..3e44f31c12ca0e706d2ab9ded107595483c409d6 100644 (file)
@@ -1596,6 +1596,8 @@ the thing.
 
 @var{pred} can also be recursively defined.  It can be @w{@code{(or
 @var{pred}@dots{})}}, meaning that satisfying any one of the @var{pred}s
+qualifies the node as the thing.  It can be @w{@code{(and
+@var{pred}@dots{})}}, meaning that satisfying all of the @var{pred}s
 qualifies the node as the thing.  It can be @w{@code{(not @var{pred})}},
 meaning that not satisfying @var{pred} qualifies the node.
 
@@ -1604,6 +1606,10 @@ list.  For example, @w{@code{(or sexp sentence)}} defines something
 that's either a @code{sexp} thing or a @code{sentence} thing, as defined
 by some other rule in the alist.
 
+There are two pre-defined predicates: @code{named} and @code{anonymous},
+that qualifies named and anonymous nodes, respectively.  They can be
+combined with @code{and} to narrow down the match.
+
 Here's an example @code{treesit-thing-settings} for C and C++:
 
 @example
@@ -1662,7 +1668,6 @@ signals @code{treesit-invalid-predicate} error.  If @var{ignore-missing}
 is @code{t}, this function doesn't signal the error when @var{thing} is
 undefined and just returns @code{nil}; but it still signals the error if
 @var{thing} is a malformed predicate.
-
 @end defun
 
 @defun treesit-thing-prev position thing
@@ -2179,8 +2184,6 @@ navigation commands that move, respectively, by sexps and sentences by
 defining variables such as @code{forward-sexp-function} and
 @code{forward-sentence-function}.
 @end itemize
-
-@c TODO: Add treesit-thing-settings stuff once we finalize it.
 @end defun
 
 For more information on these built-in tree-sitter features,
index 878c1f0b3406ce22593cd3615775a3cc1de12610..918b1a510eaf7dea715eebfbc9ba08a1938725ff 100644 (file)
@@ -3623,6 +3623,9 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
     return true;
   else if (SYMBOLP (pred))
     {
+      if (BASE_EQ (pred, Qnamed) || BASE_EQ (pred, Qanonymous))
+       return true;
+
       Lisp_Object definition = treesit_traverse_get_predicate (pred,
                                                               language);
       if (NILP (definition))
@@ -3667,13 +3670,13 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
                                                      signal_data,
                                                      recursion_level + 1);
        }
-      else if (BASE_EQ (car, Qor))
+      else if (BASE_EQ (car, Qor) || BASE_EQ (car, Qand))
        {
          if (!CONSP (cdr) || NILP (cdr))
            {
              *signal_data = list3 (Qtreesit_invalid_predicate,
-                                   build_string ("`or' must have a list "
-                                                 "of patterns as "
+                                   build_string ("`or' or `and' must have "
+                                                 "a list of patterns as "
                                                  "arguments "),
                                    pred);
              return false;
@@ -3729,6 +3732,14 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
       Lisp_Object lisp_node = make_treesit_node (parser, node);
       return !NILP (CALLN (Ffuncall, pred, lisp_node));
     }
+  else if (SYMBOLP (pred) && BASE_EQ (pred, Qnamed))
+    {
+      return ts_node_is_named (node);
+    }
+  else if (SYMBOLP (pred) && BASE_EQ (pred, Qanonymous))
+    {
+      return !ts_node_is_named (node);
+    }
   else if (SYMBOLP (pred))
     {
       Lisp_Object language = XTS_PARSER (parser)->language_symbol;
@@ -3755,6 +3766,16 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
            }
          return false;
        }
+      else if (BASE_EQ (car, Qand))
+       {
+         FOR_EACH_TAIL (cdr)
+           {
+             if (!treesit_traverse_match_predicate (cursor, XCAR (cdr),
+                                                    parser, named))
+               return false;
+           }
+         return  true;
+       }
       else if (STRINGP (car) && FUNCTIONP (cdr))
        {
          /* A bit of code duplication here, but should be fine.  */
@@ -4297,6 +4318,7 @@ syms_of_treesit (void)
   DEFSYM (Qtreesit_compiled_query_p, "treesit-compiled-query-p");
   DEFSYM (Qtreesit_query_p, "treesit-query-p");
   DEFSYM (Qnamed, "named");
+  DEFSYM (Qanonymous, "anonymous");
   DEFSYM (Qmissing, "missing");
   DEFSYM (Qextra, "extra");
   DEFSYM (Qoutdated, "outdated");
@@ -4338,6 +4360,7 @@ syms_of_treesit (void)
   DEFSYM (Qtreesit_thing_symbol, "treesit-thing-symbol");
 
   DEFSYM (Qor, "or");
+  DEFSYM (Qand, "and");
 
 #ifdef WINDOWSNT
   DEFSYM (Qtree_sitter, "tree-sitter");
@@ -4420,8 +4443,12 @@ cons (REGEXP . FN), which is a combination of a regexp and a predicate
 function, and the node has to match both to qualify as the thing.
 
 PRED can also be recursively defined.  It can be (or PRED...), meaning
-satisfying anyone of the inner PREDs qualifies the node; or (not
-PRED), meaning not satisfying the inner PRED qualifies the node.
+satisfying anyone of the inner PREDs qualifies the node; or (and
+PRED...) meaning satisfying all of the inner PREDs qualifies the node;
+or (not PRED), meaning not satisfying the inner PRED qualifies the node.
+
+There are two pre-defined predicates, `named' and `anonymous`.  They
+match named nodes and anonymous nodes, respectively.
 
 Finally, PRED can refer to other THINGs defined in this list by using
 the symbol of that THING.  For example, (or sexp sentence).  */);