From 05a5f9c124adc34278026748ba03c55e232810fd Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 12 Mar 2014 13:39:12 -0700 Subject: [PATCH] Add function for notifying documents of edits --- include/tree_sitter/runtime.h | 2 ++ spec/runtime/parser_spec.cc | 63 ++++++++++++++++++++++++++++------- src/runtime/document.c | 7 ++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index cff6a4d2..6d883ecf 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -59,6 +59,8 @@ void ts_document_free(ts_document *doc); void ts_document_set_parser(ts_document *doc, ts_parse_config parser); void ts_document_set_input(ts_document *doc, ts_input input); void ts_document_set_input_string(ts_document *doc, const char *text); +void ts_document_edit(ts_document *doc, size_t position, size_t deleted_bytes, size_t inserted_bytes); + const ts_tree * ts_document_tree(const ts_document *doc); const char * ts_document_string(const ts_document *doc); diff --git a/spec/runtime/parser_spec.cc b/spec/runtime/parser_spec.cc index 15cf1af2..895a7a86 100644 --- a/spec/runtime/parser_spec.cc +++ b/spec/runtime/parser_spec.cc @@ -5,32 +5,71 @@ extern ts_parse_config ts_parse_config_json; START_TEST -describe("reading from an input", [&]() { +describe("parsing", [&]() { ts_document *doc; + SpyReader *reader; before_each([&]() { doc = ts_document_make(); ts_document_set_parser(doc, ts_parse_config_json); + + reader = new SpyReader("{ \"key\": [1, 2] }", 5); + ts_document_set_input(doc, reader->input); }); after_each([&]() { ts_document_free(doc); + delete reader; }); + it("parses the input", [&]() { + AssertThat(string(ts_document_string(doc)), Equals( + "(value " + "(object " + "(string) " + "(value (array " + "(value (number)) " + "(value (number))))))")); + }); + it("reads the entire input", [&]() { - SpyReader reader("\"ok go do it!\"", 3); - ts_document_set_input(doc, reader.input); - - AssertThat(string(ts_document_string(doc)), Equals("(value (string))")); - AssertThat(reader.chunks_read, Equals(vector({ - "\"ok", - " go", - " do", - " it", - "!\"", + AssertThat(reader->chunks_read, Equals(vector({ + "{ \"ke", + "y\": [", + "1, 2]", + " }", "" }))); }); + + describe("modifying the input", [&]() { + before_each([&]() { + size_t position(string("{ \"key\": [1, 2]").length()); + string inserted_text(", \"key2\": 4 "); + + reader->content.insert(position, inserted_text); + ts_document_edit(doc, position, 0, inserted_text.length()); + }); + + it("updates the parse tree", [&]() { + AssertThat(string(ts_document_string(doc)), Equals( + "(value " + "(object " + "(string) " + "(value (array " + "(value (number)) " + "(value (number)))) " + "(string) " + "(value (number))))" + )); + }); + + it_skip("re-reads only the changed portion of the input", [&]() { + AssertThat(reader->chunks_read, Equals(vector({ + "" + }))); + }); + }); }); -END_TEST \ No newline at end of file +END_TEST diff --git a/src/runtime/document.c b/src/runtime/document.c index 26e33823..8a65f495 100644 --- a/src/runtime/document.c +++ b/src/runtime/document.c @@ -4,6 +4,7 @@ struct ts_document { ts_parse_config parse_config; const ts_tree *tree; + ts_input input; size_t error_count; }; @@ -28,9 +29,15 @@ const char * ts_document_string(const ts_document *document) { } void ts_document_set_input(ts_document *document, ts_input input) { + document->input = input; document->tree = document->parse_config.parse_fn(input); } +void ts_document_edit(ts_document *document, size_t position, size_t bytes_removed, size_t bytes_inserted) { + document->input.seek_fn(document->input.data, 0); + document->tree = document->parse_config.parse_fn(document->input); +} + typedef struct { const char *string; size_t position;