Add ts_node_edit API
This commit is contained in:
parent
308016b776
commit
9e8bec458d
6 changed files with 132 additions and 2 deletions
|
|
@ -131,6 +131,7 @@ TSNode ts_node_descendant_for_byte_range(TSNode, uint32_t, uint32_t);
|
|||
TSNode ts_node_named_descendant_for_byte_range(TSNode, uint32_t, uint32_t);
|
||||
TSNode ts_node_descendant_for_point_range(TSNode, TSPoint, TSPoint);
|
||||
TSNode ts_node_named_descendant_for_point_range(TSNode, TSPoint, TSPoint);
|
||||
void ts_node_edit(TSNode *, const TSInputEdit *);
|
||||
|
||||
TSTreeCursor ts_tree_cursor_new(TSNode);
|
||||
void ts_tree_cursor_delete(TSTreeCursor *);
|
||||
|
|
|
|||
|
|
@ -494,3 +494,20 @@ TSNode ts_node_named_descendant_for_point_range(TSNode self, TSPoint min,
|
|||
TSPoint max) {
|
||||
return ts_node__descendant_for_point_range(self, min, max, false);
|
||||
}
|
||||
|
||||
void ts_node_edit(TSNode *self, const TSInputEdit *edit) {
|
||||
uint32_t start_byte = ts_node_start_byte(*self);
|
||||
TSPoint start_point = ts_node_start_point(*self);
|
||||
|
||||
if (start_byte >= edit->old_end_byte) {
|
||||
start_byte = edit->new_end_byte + (start_byte - edit->old_end_byte);
|
||||
start_point = point_add(edit->new_end_point, point_sub(start_point, edit->old_end_point));
|
||||
} else if (start_byte > edit->start_byte) {
|
||||
start_byte = edit->new_end_byte;
|
||||
start_point = edit->new_end_point;
|
||||
}
|
||||
|
||||
self->context[0] = start_byte;
|
||||
self->context[1] = start_point.row;
|
||||
self->context[2] = start_point.column;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,16 @@
|
|||
#include "compiler/lexical_grammar.h"
|
||||
#include "compiler/build_tables/parse_item.h"
|
||||
#include "compiler/build_tables/lex_item.h"
|
||||
#include "helpers/point_helpers.h"
|
||||
|
||||
ostream &operator<<(ostream &stream, const TSInputEdit &edit) {
|
||||
return stream << "{TSInputEdit start_byte: " << edit.start_byte <<
|
||||
", old_end_byte: " << edit.old_end_byte <<
|
||||
", new_end_byte: " << edit.new_end_byte <<
|
||||
", start_point: " << edit.start_point <<
|
||||
", old_end_point: " << edit.old_end_point <<
|
||||
", new_end_point: " << edit.new_end_point << "}";
|
||||
}
|
||||
|
||||
namespace tree_sitter {
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "tree_sitter/runtime.h"
|
||||
#include "compiler/grammar.h"
|
||||
#include "compiler/prepare_grammar/interned_grammar.h"
|
||||
#include "compiler/prepare_grammar/initial_syntax_grammar.h"
|
||||
|
|
@ -91,6 +92,8 @@ inline std::ostream& operator<<(std::ostream &stream, const std::pair<T1, T2> &p
|
|||
|
||||
} // namespace std
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const TSInputEdit &);
|
||||
|
||||
namespace tree_sitter {
|
||||
|
||||
using std::ostream;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,10 @@ ostream &operator<<(ostream &stream, const TSNode &node) {
|
|||
}
|
||||
|
||||
bool operator==(const TSNode &left, const TSNode &right) {
|
||||
return ts_node_eq(left, right);
|
||||
return
|
||||
left.id == right.id &&
|
||||
ts_node_start_byte(left) == ts_node_start_byte(right) &&
|
||||
ts_node_start_point(left) == ts_node_start_point(right);
|
||||
}
|
||||
|
||||
bool operator==(const std::vector<const Subtree *> &vec, const SubtreeArray &array) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "test_helper.h"
|
||||
#include "runtime/alloc.h"
|
||||
#include "helpers/tree_helpers.h"
|
||||
|
|
@ -6,6 +5,8 @@
|
|||
#include "helpers/load_language.h"
|
||||
#include "helpers/record_alloc.h"
|
||||
#include "helpers/stream_methods.h"
|
||||
#include "helpers/random_helpers.h"
|
||||
#include "helpers/spy_input.h"
|
||||
|
||||
START_TEST
|
||||
|
||||
|
|
@ -556,6 +557,101 @@ describe("Node", [&]() {
|
|||
AssertThat(ts_node_start_point(array_node), Equals<TSPoint>({7, 0}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("edit(edit)", [&]() {
|
||||
vector<pair<string, TSInputEdit>> test_table = {
|
||||
{
|
||||
"insert 5 lines at the beginning",
|
||||
{
|
||||
0, 0, 5,
|
||||
{0, 0}, {0, 0}, {5, 0}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
"delete first 5 lines",
|
||||
{
|
||||
0, (uint32_t)object_index, 0,
|
||||
{0, 0}, {5, 2}, {0, 0}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
"replace entire text",
|
||||
{
|
||||
0, (uint32_t)json_string.size(), 5,
|
||||
{0, 0}, {9, 0}, {0, 5}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto get_all_nodes = [&]() {
|
||||
vector<TSNode> result;
|
||||
bool visited_children = false;
|
||||
TSTreeCursor cursor = ts_tree_cursor_new(ts_tree_root_node(tree));
|
||||
while (true) {
|
||||
result.push_back(ts_tree_cursor_current_node(&cursor));
|
||||
if (!visited_children && ts_tree_cursor_goto_first_child(&cursor)) continue;
|
||||
if (ts_tree_cursor_goto_next_sibling(&cursor)) {
|
||||
visited_children = false;
|
||||
} else if (ts_tree_cursor_goto_parent(&cursor)) {
|
||||
visited_children = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ts_tree_cursor_delete(&cursor);
|
||||
return result;
|
||||
};
|
||||
|
||||
for (auto &entry : test_table) {
|
||||
const string &description = entry.first;
|
||||
const TSInputEdit &edit = entry.second;
|
||||
|
||||
it(("updates the node's start position according to edit - " + description).c_str(), [&]() {
|
||||
auto nodes_before = get_all_nodes();
|
||||
|
||||
ts_tree_edit(tree, &edit);
|
||||
for (TSNode &node : nodes_before) {
|
||||
ts_node_edit(&node, &edit);
|
||||
}
|
||||
|
||||
auto nodes_after = get_all_nodes();
|
||||
|
||||
for (unsigned i = 0; i < nodes_before.size(); i++) {
|
||||
TSNode &node_before = nodes_before[i];
|
||||
TSNode &node_after = nodes_after[i];
|
||||
AssertThat(node_before, Equals(node_after));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
it("updates the node's start position according to edit - random edits", [&]() {
|
||||
SpyInput input(json_string, 3);
|
||||
|
||||
for (unsigned i = 0; i < 10; i++) {
|
||||
auto nodes_before = get_all_nodes();
|
||||
|
||||
size_t edit_start = default_generator(input.content.size());
|
||||
size_t deletion_size = default_generator(2) ? 0 : default_generator(input.content.size() - edit_start);
|
||||
string inserted_text = default_generator.words(default_generator(4) + 1);
|
||||
|
||||
TSInputEdit edit = input.replace(edit_start, deletion_size, inserted_text);
|
||||
ts_tree_edit(tree, &edit);
|
||||
for (TSNode &node : nodes_before) {
|
||||
ts_node_edit(&node, &edit);
|
||||
}
|
||||
|
||||
auto nodes_after = get_all_nodes();
|
||||
|
||||
for (unsigned i = 0; i < nodes_before.size(); i++) {
|
||||
TSNode &node_before = nodes_before[i];
|
||||
TSNode &node_after = nodes_after[i];
|
||||
AssertThat(node_before, Equals(node_after));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("TreeCursor", [&]() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue