emacs-diffs
[Top][All Lists]
Advanced

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

feature/tree-sitter 34e50dc4a2 2/5: Allow tree-sitter to notify parse-tr


From: Yuan Fu
Subject: feature/tree-sitter 34e50dc4a2 2/5: Allow tree-sitter to notify parse-tree changes
Date: Tue, 15 Nov 2022 05:49:25 -0500 (EST)

branch: feature/tree-sitter
commit 34e50dc4a23505dce0499f120477e2e1a1327432
Author: Yuan Fu <casouri@gmail.com>
Commit: Yuan Fu <casouri@gmail.com>

    Allow tree-sitter to notify parse-tree changes
    
    * src/treesit.c (treesit_call_after_change_functions): New function.
    (treesit_ensure_parsed): Call treesit_call_after_change_functions
    right after re-parse.
    (make_treesit_parser): Initialize after_change_functions.
    (Ftreesit_parser_notifiers)
    (Ftreesit_parser_add_notifier)
    (Ftreesit_parser_remove_notifier): New functions.
    * src/treesit.h (Lisp_TS_Parser): New field after_change_functions.
---
 src/treesit.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/treesit.h |  4 +++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/src/treesit.c b/src/treesit.c
index a70a199cfe..858148b849 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -843,6 +843,30 @@ treesit_check_buffer_size (struct buffer *buffer)
              make_fixnum (buffer_size));
 }
 
+static Lisp_Object
+treesit_make_ranges (const TSRange *, uint32_t, struct buffer *);
+
+static void
+treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree,
+                                    Lisp_Object parser)
+{
+  uint32_t len;
+  TSRange *ranges = ts_tree_get_changed_ranges (old_tree, new_tree, &len);
+  struct buffer *buf = XBUFFER (XTS_PARSER (parser)->buffer);
+  Lisp_Object lisp_ranges = treesit_make_ranges(ranges, len, buf);
+  xfree (ranges);
+
+  specpdl_ref count = SPECPDL_INDEX ();
+
+  /* let's trust the after change functions and not clone a new ranges
+     for each of them.  */
+  Lisp_Object functions = XTS_PARSER (parser)->after_change_functions;
+  FOR_EACH_TAIL (functions)
+    safe_call2(XCAR (functions), lisp_ranges, parser);
+
+  unbind_to (count, Qnil);
+}
+
 /* Parse the buffer.  We don't parse until we have to.  When we have
    to, we call this function to parse and update the tree.  */
 static void
@@ -875,7 +899,11 @@ treesit_ensure_parsed (Lisp_Object parser)
     }
 
   if (tree != NULL)
-    ts_tree_delete (tree);
+    {
+      treesit_call_after_change_functions(tree, new_tree, parser);
+      ts_tree_delete (tree);
+    }
+
   XTS_PARSER (parser)->tree = new_tree;
   XTS_PARSER (parser)->need_reparse = false;
 }
@@ -945,6 +973,7 @@ make_treesit_parser (Lisp_Object buffer, TSParser *parser,
                                       buffer, PVEC_TS_PARSER);
 
   lisp_parser->language_symbol = language_symbol;
+  lisp_parser->after_change_functions = Qnil;
   lisp_parser->buffer = buffer;
   lisp_parser->parser = parser;
   lisp_parser->tree = tree;
@@ -1473,6 +1502,57 @@ return nil.  */)
   return treesit_make_ranges (ranges, len, buffer);
 }
 
+DEFUN ("treesit-parser-notifiers",
+       Ftreesit_parser_notifiers,
+       Streesit_parser_notifiers,
+       1, 1, 0,
+       doc: /* Return the after-change functions for PARSER.  */)
+  (Lisp_Object parser)
+{
+  treesit_check_parser (parser);
+
+  Lisp_Object return_list = Qnil;
+  Lisp_Object tail = XTS_PARSER (parser)->after_change_functions;
+  FOR_EACH_TAIL (tail)
+    return_list = Fcons (XCAR (tail), return_list);
+
+  return return_list;
+}
+
+DEFUN ("treesit-parser-add-notifier",
+       Ftreesit_parser_add_notifier,
+       Streesit_parser_add_notifier,
+       2, 2, 0,
+       doc: /* Add FUNCTION to PARSER's after-change notifiers.  */)
+  (Lisp_Object parser, Lisp_Object function)
+{
+  treesit_check_parser (parser);
+  /* For simplicity we don't accept lambda functions.  */
+  CHECK_SYMBOL (function);
+
+  Lisp_Object functions = XTS_PARSER (parser)->after_change_functions;
+  if (!Fmemq (function, functions))
+    XTS_PARSER (parser)->after_change_functions = Fcons (function, functions);
+  return Qnil;
+}
+
+DEFUN ("treesit-parser-remove-notifier",
+       Ftreesit_parser_remove_notifier,
+       Streesit_parser_remove_notifier,
+       2, 2, 0,
+       doc: /* Remove FUNCTION from PARSER's after-change notifiers.  */)
+  (Lisp_Object parser, Lisp_Object function)
+{
+  treesit_check_parser (parser);
+  /* For simplicity we don't accept lambda functions.  */
+  CHECK_SYMBOL (function);
+
+  Lisp_Object functions = XTS_PARSER (parser)->after_change_functions;
+  if (Fmemq (function, functions))
+    XTS_PARSER (parser)->after_change_functions = Fdelq (function, functions);
+  return Qnil;
+}
+
 /*** Node API  */
 
 /* Check that OBJ is a positive integer and signal an error if
@@ -2934,6 +3014,10 @@ then in the system default locations for dynamic 
libraries, in that order.  */);
   defsubr (&Streesit_parser_set_included_ranges);
   defsubr (&Streesit_parser_included_ranges);
 
+  defsubr (&Streesit_parser_notifiers);
+  defsubr (&Streesit_parser_add_notifier);
+  defsubr (&Streesit_parser_remove_notifier);
+
   defsubr (&Streesit_node_type);
   defsubr (&Streesit_node_start);
   defsubr (&Streesit_node_end);
diff --git a/src/treesit.h b/src/treesit.h
index 169d8819d7..2d2a91cd36 100644
--- a/src/treesit.h
+++ b/src/treesit.h
@@ -33,6 +33,10 @@ struct Lisp_TS_Parser
   /* A symbol representing the language this parser uses.  See the
      manual for more explanation.  */
   Lisp_Object language_symbol;
+  /* A list of functions to call after re-parse.  Every function is
+     called with the changed ranges and the parser.  The changed
+     ranges is a list of (BEG . END).  */
+  Lisp_Object after_change_functions;
   /* The buffer associated with this parser.  */
   Lisp_Object buffer;
   /* The pointer to the tree-sitter parser.  Never NULL.  */



reply via email to

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