From 074c0510949f4afde3d65c5a0ae85f8a8c7a1b1c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 17 May 2018 11:14:51 -0700 Subject: [PATCH] Change the TSInputEdit struct to work with old/new start and end positions --- include/tree_sitter/runtime.h | 8 ++--- src/runtime/subtree.c | 55 +++++++++++++++---------------- test/helpers/spy_input.cc | 25 +++++++++----- test/runtime/subtree_test.cc | 62 +++++++++++++++++++---------------- 4 files changed, 81 insertions(+), 69 deletions(-) diff --git a/include/tree_sitter/runtime.h b/include/tree_sitter/runtime.h index ea52d4c2..6a6767e9 100644 --- a/include/tree_sitter/runtime.h +++ b/include/tree_sitter/runtime.h @@ -57,11 +57,11 @@ typedef struct { typedef struct { uint32_t start_byte; - uint32_t bytes_removed; - uint32_t bytes_added; + uint32_t old_end_byte; + uint32_t new_end_byte; TSPoint start_point; - TSPoint extent_removed; - TSPoint extent_added; + TSPoint old_end_point; + TSPoint new_end_point; } TSInputEdit; typedef struct { diff --git a/src/runtime/subtree.c b/src/runtime/subtree.c index 0991b67c..9b2d954f 100644 --- a/src/runtime/subtree.c +++ b/src/runtime/subtree.c @@ -13,8 +13,8 @@ typedef struct { Length start; - Length added; - Length removed; + Length old_end; + Length new_end; } Edit; TSStateId TS_TREE_STATE_NONE = USHRT_MAX; @@ -490,22 +490,23 @@ const Subtree *ts_subtree_invalidate_lookahead(const Subtree *self, uint32_t edi } const Subtree *ts_subtree__edit(const Subtree *self, Edit edit, SubtreePool *pool) { - Length new_end = length_add(edit.start, edit.added); - Length old_end = length_add(edit.start, edit.removed); - Subtree *result = ts_subtree_make_mut(pool, self); result->has_changes = true; - if (old_end.bytes <= result->padding.bytes) { - result->padding = length_add(new_end, length_sub(result->padding, old_end)); + bool pure_insertion = edit.old_end.bytes == edit.start.bytes; + + if (edit.old_end.bytes <= result->padding.bytes) { + result->padding = length_add(edit.new_end, length_sub(result->padding, edit.old_end)); } else if (edit.start.bytes < result->padding.bytes) { - result->size = length_sub(result->size, length_sub(old_end, result->padding)); - result->padding = new_end; - } else if (edit.start.bytes == result->padding.bytes && edit.removed.bytes == 0) { - result->padding = length_add(result->padding, edit.added); + result->size = length_sub(result->size, length_sub(edit.old_end, result->padding)); + result->padding = edit.new_end; + } else if (edit.start.bytes == result->padding.bytes && pure_insertion) { + result->padding = edit.new_end; } else { - Length new_total_size = length_add(new_end, length_sub(ts_subtree_total_size(result), old_end)); - result->size = length_sub(new_total_size, result->padding); + result->size = length_add( + length_sub(edit.new_end, result->padding), + length_sub(result->size, length_sub(edit.old_end, result->padding)) + ); } Length child_left, child_right = length_zero(); @@ -515,27 +516,23 @@ const Subtree *ts_subtree__edit(const Subtree *self, Edit edit, SubtreePool *poo child_left = child_right; child_right = length_add(child_left, child_size); - if (child_left.bytes > old_end.bytes || - (child_left.bytes == old_end.bytes && child_size.bytes > 0 && i > 0)) break; + if (child_left.bytes > edit.old_end.bytes || + (child_left.bytes == edit.old_end.bytes && child_size.bytes > 0 && i > 0)) break; if (child_right.bytes > edit.start.bytes || - (child_right.bytes == edit.start.bytes && edit.removed.bytes == 0)) { + (child_right.bytes == edit.start.bytes && pure_insertion)) { Edit child_edit = { .start = length_sub(edit.start, child_left), - .added = edit.added, - .removed = edit.removed, + .old_end = length_sub(edit.old_end, child_left), + .new_end = length_sub(edit.new_end, child_left), }; - if (edit.start.bytes < child_left.bytes) { - child_edit.start = length_zero(); - } + if (edit.start.bytes < child_left.bytes) child_edit.start = length_zero(); + if (edit.old_end.bytes < child_left.bytes) child_edit.old_end = length_zero(); + if (edit.new_end.bytes < child_left.bytes) child_edit.new_end = length_zero(); + if (edit.old_end.bytes > child_right.bytes) child_edit.old_end = child_size; - if (old_end.bytes > child_right.bytes) { - child_edit.removed = length_sub(child_size, child_edit.start); - } - - edit.added = length_zero(); - edit.removed = length_sub(edit.removed, child_edit.removed); + edit.new_end = edit.start; *child = ts_subtree__edit(*child, child_edit, pool); } else if (child_left.bytes <= edit.start.bytes) { @@ -549,8 +546,8 @@ const Subtree *ts_subtree__edit(const Subtree *self, Edit edit, SubtreePool *poo const Subtree *ts_subtree_edit(const Subtree *self, const TSInputEdit *edit, SubtreePool *pool) { return ts_subtree__edit(self, (Edit) { .start = {edit->start_byte, edit->start_point}, - .added = {edit->bytes_added, edit->extent_added}, - .removed = {edit->bytes_removed, edit->extent_removed}, + .old_end = {edit->old_end_byte, edit->old_end_point}, + .new_end = {edit->new_end_byte, edit->new_end_point}, }, pool); } diff --git a/test/helpers/spy_input.cc b/test/helpers/spy_input.cc index 889dcdf0..6126f101 100644 --- a/test/helpers/spy_input.cc +++ b/test/helpers/spy_input.cc @@ -1,5 +1,6 @@ #include "helpers/spy_input.h" #include "helpers/encoding_helpers.h" +#include "runtime/point.h" #include #include #include @@ -20,6 +21,14 @@ SpyInput::~SpyInput() { delete[] buffer; } +static TSPoint operator+(TSPoint a, TSPoint b) { + if (b.row > 0) { + return TSPoint {a.row + b.row, b.column}; + } else { + return TSPoint {a.row, a.column + b.column}; + } +} + static void add_byte_range(vector> *ranges, uint32_t start, uint32_t count) { uint32_t end = start + count; @@ -112,11 +121,11 @@ TSInputEdit SpyInput::replace(size_t start_byte, size_t bytes_removed, string te undo_stack.push_back(SpyInputEdit{start_byte, bytes_added, swap.first}); TSInputEdit result = {}; result.start_byte = start_byte; - result.bytes_added = bytes_added; - result.bytes_removed = bytes_removed; + result.old_end_byte = start_byte + bytes_removed; + result.new_end_byte = start_byte + bytes_added; result.start_point = swap.second; - result.extent_removed = get_extent(swap.first); - result.extent_added = get_extent(text); + result.old_end_point = result.start_point + get_extent(swap.first); + result.new_end_point = result.start_point + get_extent(text); return result; } @@ -126,11 +135,11 @@ TSInputEdit SpyInput::undo() { auto swap = swap_substr(entry.start_byte, entry.bytes_removed, entry.text_inserted); TSInputEdit result; result.start_byte = entry.start_byte; - result.bytes_removed = entry.bytes_removed; - result.bytes_added = entry.text_inserted.size(); + result.old_end_byte = entry.start_byte + entry.bytes_removed; + result.new_end_byte = entry.start_byte + entry.text_inserted.size(); result.start_point = swap.second; - result.extent_removed = get_extent(swap.first); - result.extent_added = get_extent(entry.text_inserted); + result.old_end_point = result.start_point + get_extent(swap.first); + result.new_end_point = result.start_point + get_extent(entry.text_inserted); return result; } diff --git a/test/runtime/subtree_test.cc b/test/runtime/subtree_test.cc index 3c1c9ad2..246f985e 100644 --- a/test/runtime/subtree_test.cc +++ b/test/runtime/subtree_test.cc @@ -202,11 +202,11 @@ describe("Subtree", []() { it("does not mutate the argument", [&]() { TSInputEdit edit; edit.start_byte = 1; - edit.bytes_removed = 0; - edit.bytes_added = 1; + edit.old_end_byte = 1; + edit.new_end_byte = 2; edit.start_point = {0, 1}; - edit.extent_removed = {0, 0}; - edit.extent_added = {0, 1}; + edit.old_end_point = {0, 1}; + edit.new_end_point = {0, 2}; ts_subtree_retain(tree); const Subtree *new_tree = ts_subtree_edit(tree, &edit, &pool); @@ -232,11 +232,12 @@ describe("Subtree", []() { it("resizes the padding of the tree and its leftmost descendants", [&]() { TSInputEdit edit; edit.start_byte = 1; - edit.bytes_removed = 0; - edit.bytes_added = 1; + edit.old_end_byte = 1; + edit.new_end_byte = 2; edit.start_point = {0, 1}; - edit.extent_removed = {0, 0}; - edit.extent_added = {0, 1}; + edit.old_end_point = {0, 1}; + edit.new_end_point = {0, 2}; + tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree); @@ -258,11 +259,12 @@ describe("Subtree", []() { it("shrinks the content to compensate for the expanded padding", [&]() { TSInputEdit edit; edit.start_byte = 1; - edit.bytes_removed = 3; - edit.bytes_added = 4; + edit.old_end_byte = 4; + edit.new_end_byte = 5; edit.start_point = {0, 1}; - edit.extent_removed = {0, 3}; - edit.extent_added = {0, 4}; + edit.old_end_point = {0, 4}; + edit.new_end_point = {0, 5}; + tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree); @@ -280,11 +282,12 @@ describe("Subtree", []() { it("expands the tree's padding", [&]() { TSInputEdit edit; edit.start_byte = 2; - edit.bytes_removed = 0; - edit.bytes_added = 2; + edit.old_end_byte = 2; + edit.new_end_byte = 4; edit.start_point = {0, 2}; - edit.extent_removed = {0, 0}; - edit.extent_added = {0, 2}; + edit.old_end_point = {0, 2}; + edit.new_end_point = {0, 4}; + tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree); @@ -304,11 +307,12 @@ describe("Subtree", []() { it("resizes the content and not the padding", [&]() { TSInputEdit edit; edit.start_byte = 2; - edit.bytes_removed = 2; - edit.bytes_added = 5; + edit.old_end_byte = 4; + edit.new_end_byte = 7; edit.start_point = {0, 2}; - edit.extent_removed = {0, 2}; - edit.extent_added = {0, 5}; + edit.old_end_point = {0, 4}; + edit.new_end_point = {0, 7}; + tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree); @@ -328,11 +332,12 @@ describe("Subtree", []() { it("shrinks subsequent child nodes", [&]() { TSInputEdit edit; edit.start_byte = 1; - edit.bytes_removed = 10; - edit.bytes_added = 3; + edit.old_end_byte = 11; + edit.new_end_byte = 4; edit.start_point = {0, 1}; - edit.extent_removed = {0, 10}; - edit.extent_added = {0, 3}; + edit.old_end_point = {0, 11}; + edit.new_end_point = {0, 4}; + tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree); @@ -361,11 +366,12 @@ describe("Subtree", []() { TSInputEdit edit; edit.start_byte = 6; - edit.bytes_removed = 1; - edit.bytes_added = 1; + edit.old_end_byte = 7; + edit.new_end_byte = 7; edit.start_point = {0, 6}; - edit.extent_removed = {0, 1}; - edit.extent_added = {0, 1}; + edit.old_end_point = {0, 7}; + edit.new_end_point = {0, 7}; + tree = ts_subtree_edit(tree, &edit, &pool); assert_consistent(tree);