[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. */