From 25d63d68f7c0300a250c10f159598b8344afe0bc Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 16 Oct 2016 20:42:55 -0700 Subject: [PATCH] Move TreePath functions into their own file --- src/runtime/document.c | 214 +--------------------------------------- src/runtime/tree_path.h | 208 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 209 deletions(-) create mode 100644 src/runtime/tree_path.h diff --git a/src/runtime/document.c b/src/runtime/document.c index 9afa33c2..ec664c45 100644 --- a/src/runtime/document.c +++ b/src/runtime/document.c @@ -5,6 +5,7 @@ #include "runtime/parser.h" #include "runtime/string_input.h" #include "runtime/document.h" +#include "runtime/tree_path.h" TSDocument *ts_document_new() { TSDocument *self = ts_calloc(1, sizeof(TSDocument)); @@ -89,212 +90,10 @@ void ts_document_edit(TSDocument *self, TSInputEdit edit) { ts_tree_edit(self->tree, &edit); } -typedef Array(TSRange) RangeArray; - -#define NAME(t) \ - ((t) \ - ? (ts_language_symbol_name(doc->parser.language, ((TSTree *)(t))->symbol)) \ - : "") - -static bool push_change(RangeArray *results, TSPoint start, TSPoint end) { - if (results->size > 0) { - TSRange *last_range = array_back(results); - if (ts_point_lte(start, last_range->end)) { - last_range->end = end; - return true; - } - } - - if (ts_point_lt(start, end)) { - TSRange range = { start, end }; - return array_push(results, range); - } - - return true; -} - -static bool tree_path_descend(TreePath *path, TSPoint position) { - bool did_descend; - do { - did_descend = false; - TreePathEntry entry = *array_back(path); - TSLength child_position = entry.position; - for (size_t i = 0; i < entry.tree->child_count; i++) { - TSTree *child = entry.tree->children[i]; - TSLength child_right_position = - ts_length_add(child_position, ts_tree_total_size(child)); - if (ts_point_lt(position, child_right_position.extent)) { - TreePathEntry child_entry = { child, child_position, i }; - if (child->visible) { - array_push(path, child_entry); - return true; - } else if (child->visible_child_count > 0) { - array_push(path, child_entry); - did_descend = true; - break; - } - } - child_position = child_right_position; - } - } while (did_descend); - return false; -} - -static size_t tree_path_advance(TreePath *path) { - size_t ascend_count = 0; - while (path->size > 0) { - TreePathEntry entry = array_pop(path); - if (path->size == 0) - break; - TreePathEntry parent_entry = *array_back(path); - if (parent_entry.tree->visible) { - ascend_count++; - } - TSLength position = - ts_length_add(entry.position, ts_tree_total_size(entry.tree)); - for (size_t i = entry.child_index + 1, n = parent_entry.tree->child_count; - i < n; i++) { - TSTree *next_child = parent_entry.tree->children[i]; - if (next_child->visible || next_child->visible_child_count > 0) { - if (parent_entry.tree->visible) { - ascend_count--; - } - array_push(path, - ((TreePathEntry){ - .tree = next_child, .child_index = i, .position = position, - })); - if (!next_child->visible) - tree_path_descend(path, (TSPoint){ 0, 0 }); - return ascend_count; - } - position = ts_length_add(position, ts_tree_total_size(next_child)); - } - } - return ascend_count; -} - -static void tree_path_ascend(TreePath *path, size_t count) { - for (size_t i = 0; i < count; i++) { - do { - array_pop(path); - } while (path->size > 0 && !array_back(path)->tree->visible); - } -} - -static void tree_path_init(TreePath *path, TSTree *tree) { - array_clear(path); - array_push(path, - ((TreePathEntry){ - .tree = tree, .position = { 0, 0, { 0, 0 } }, .child_index = 0, - })); - if (!tree->visible) - tree_path_descend(path, (TSPoint){ 0, 0 }); -} - -static bool ts_tree_get_changes(TSDocument *doc, TreePath *old_path, - TreePath *new_path, size_t depth, - RangeArray *results) { - TSPoint position = { 0, 0 }; - - while (old_path->size && new_path->size) { - bool is_different = false; - TSPoint next_position = position; - - TreePathEntry old_entry = *array_back(old_path); - TreePathEntry new_entry = *array_back(new_path); - TSTree *old_tree = old_entry.tree; - TSTree *new_tree = new_entry.tree; - TSSymbol old_symbol = old_tree->symbol; - TSSymbol new_symbol = new_tree->symbol; - size_t old_start_byte = old_entry.position.bytes; - size_t new_start_byte = new_entry.position.bytes; - size_t old_end_byte = old_start_byte + ts_tree_total_bytes(old_tree); - size_t new_end_byte = new_start_byte + ts_tree_total_bytes(new_tree); - TSPoint old_start_point = - ts_point_add(old_entry.position.extent, old_tree->padding.extent); - TSPoint new_start_point = - ts_point_add(new_entry.position.extent, new_tree->padding.extent); - TSPoint old_end_point = ts_point_add(old_start_point, old_tree->size.extent); - TSPoint new_end_point = ts_point_add(new_start_point, new_tree->size.extent); - - // printf("At [%-2lu, %-2lu] Compare (%-20s\t [%-2lu, %-2lu] - [%lu, %lu])\tvs\t(%-20s\t [%lu, %lu] - [%lu, %lu])\t", - // position.row, position.column, NAME(old_tree), old_start_point.row, - // old_start_point.column, old_end_point.row, old_end_point.column, - // NAME(new_tree), new_start_point.row, new_start_point.column, - // new_end_point.row, new_end_point.column); - - if (ts_point_lt(position, old_start_point)) { - if (ts_point_lt(position, new_start_point)) { - next_position = ts_point_min(old_start_point, new_start_point); - } else { - is_different = true; - next_position = old_start_point; - } - } else if (ts_point_lt(position, new_start_point)) { - is_different = true; - next_position = new_start_point; - } else { - if (old_tree == new_tree || - (!old_tree->has_changes && old_symbol == new_symbol && - old_start_byte == new_start_byte && old_end_byte == new_end_byte && - old_tree->parse_state != TS_TREE_STATE_NONE && - new_tree->parse_state != TS_TREE_STATE_NONE)) { - next_position = old_end_point; - } else if (old_symbol == new_symbol) { - bool old_descended = tree_path_descend(old_path, position); - bool new_descended = tree_path_descend(new_path, position); - if (old_descended) { - if (!new_descended) { - tree_path_ascend(old_path, 1); - is_different = true; - next_position = new_end_point; - } - } else if (new_descended) { - tree_path_ascend(new_path, 1); - is_different = true; - next_position = old_end_point; - } else { - next_position = ts_point_min(old_end_point, new_end_point); - } - } else { - is_different = true; - next_position = ts_point_min(old_end_point, new_end_point); - } - } - - bool advance_old = ts_point_lte(old_end_point, next_position); - bool advance_new = ts_point_lte(new_end_point, next_position); - - if (advance_new && advance_old) { - size_t old_ascend_count = tree_path_advance(old_path); - size_t new_ascend_count = tree_path_advance(new_path); - if (old_ascend_count > new_ascend_count) { - tree_path_ascend(new_path, old_ascend_count - new_ascend_count); - } else if (new_ascend_count > old_ascend_count) { - tree_path_ascend(old_path, new_ascend_count - old_ascend_count); - } - } else if (advance_new) { - size_t ascend_count = tree_path_advance(new_path); - tree_path_ascend(old_path, ascend_count); - } else if (advance_old) { - size_t ascend_count = tree_path_advance(old_path); - tree_path_ascend(new_path, ascend_count); - } - - if (is_different) - push_change(results, position, next_position); - position = next_position; - } - - return true; -} - int ts_document_parse_and_get_changed_ranges(TSDocument *self, TSRange **ranges, size_t *range_count) { - if (ranges) - *ranges = NULL; - if (range_count) - *range_count = 0; + if (ranges) *ranges = NULL; + if (range_count) *range_count = 0; if (!self->input.read || !self->parser.language) return -1; @@ -312,14 +111,11 @@ int ts_document_parse_and_get_changed_ranges(TSDocument *self, TSRange **ranges, self->tree = tree; if (ranges && range_count) { - RangeArray result = { 0, 0, 0 }; tree_path_init(&self->parser.tree_path1, old_tree); tree_path_init(&self->parser.tree_path2, tree); - if (!ts_tree_get_changes(self, &self->parser.tree_path1, - &self->parser.tree_path2, 0, &result)) + if (!tree_path_get_changes(&self->parser.tree_path1, + &self->parser.tree_path2, ranges, range_count)) return -1; - *ranges = result.contents; - *range_count = result.size; } ts_tree_release(old_tree); diff --git a/src/runtime/tree_path.h b/src/runtime/tree_path.h new file mode 100644 index 00000000..52100092 --- /dev/null +++ b/src/runtime/tree_path.h @@ -0,0 +1,208 @@ +#ifndef RUNTIME_TREE_PATH_H_ +#define RUNTIME_TREE_PATH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "runtime/tree.h" + +typedef Array(TSRange) RangeArray; + +static bool range_array_add(RangeArray *results, TSPoint start, TSPoint end) { + if (results->size > 0) { + TSRange *last_range = array_back(results); + if (ts_point_lte(start, last_range->end)) { + last_range->end = end; + return true; + } + } + + if (ts_point_lt(start, end)) { + TSRange range = { start, end }; + return array_push(results, range); + } + + return true; +} + +static bool tree_path_descend(TreePath *path, TSPoint position) { + bool did_descend; + do { + did_descend = false; + TreePathEntry entry = *array_back(path); + TSLength child_position = entry.position; + for (size_t i = 0; i < entry.tree->child_count; i++) { + TSTree *child = entry.tree->children[i]; + TSLength child_right_position = + ts_length_add(child_position, ts_tree_total_size(child)); + if (ts_point_lt(position, child_right_position.extent)) { + TreePathEntry child_entry = { child, child_position, i }; + if (child->visible) { + array_push(path, child_entry); + return true; + } else if (child->visible_child_count > 0) { + array_push(path, child_entry); + did_descend = true; + break; + } + } + child_position = child_right_position; + } + } while (did_descend); + return false; +} + +static size_t tree_path_advance(TreePath *path) { + size_t ascend_count = 0; + while (path->size > 0) { + TreePathEntry entry = array_pop(path); + if (path->size == 0) + break; + TreePathEntry parent_entry = *array_back(path); + if (parent_entry.tree->visible) ascend_count++; + TSLength position = + ts_length_add(entry.position, ts_tree_total_size(entry.tree)); + for (size_t i = entry.child_index + 1; i < parent_entry.tree->child_count; i++) { + TSTree *next_child = parent_entry.tree->children[i]; + if (next_child->visible || next_child->visible_child_count > 0) { + if (parent_entry.tree->visible) ascend_count--; + array_push(path, ((TreePathEntry){ + .tree = next_child, + .child_index = i, + .position = position, + })); + if (!next_child->visible) + tree_path_descend(path, (TSPoint){ 0, 0 }); + return ascend_count; + } + position = ts_length_add(position, ts_tree_total_size(next_child)); + } + } + return ascend_count; +} + +static void tree_path_ascend(TreePath *path, size_t count) { + for (size_t i = 0; i < count; i++) { + do { + array_pop(path); + } while (path->size > 0 && !array_back(path)->tree->visible); + } +} + +static void tree_path_init(TreePath *path, TSTree *tree) { + array_clear(path); + array_push(path, + ((TreePathEntry){ + .tree = tree, .position = { 0, 0, { 0, 0 } }, .child_index = 0, + })); + if (!tree->visible) + tree_path_descend(path, (TSPoint){ 0, 0 }); +} + +static bool tree_must_eq(TSTree *old_tree, TSTree *new_tree) { + return old_tree == new_tree || ( + !old_tree->has_changes && + old_tree->symbol == new_tree->symbol && + old_tree->size.bytes == new_tree->size.bytes && + old_tree->parse_state != TS_TREE_STATE_NONE && + new_tree->parse_state != TS_TREE_STATE_NONE && + (old_tree->parse_state == TS_STATE_ERROR) == + (new_tree->parse_state == TS_STATE_ERROR) + ); +} + +static bool tree_path_get_changes(TreePath *old_path, TreePath *new_path, + TSRange **ranges, size_t *range_count) { + TSPoint position = { 0, 0 }; + RangeArray results = array_new(); + + while (old_path->size && new_path->size) { + bool is_changed = false; + TSPoint next_position = position; + + TreePathEntry old_entry = *array_back(old_path); + TreePathEntry new_entry = *array_back(new_path); + TSTree *old_tree = old_entry.tree; + TSTree *new_tree = new_entry.tree; + size_t old_start_byte = old_entry.position.bytes + old_tree->padding.bytes; + size_t new_start_byte = new_entry.position.bytes + new_tree->padding.bytes; + TSPoint old_start_point = + ts_point_add(old_entry.position.extent, old_tree->padding.extent); + TSPoint new_start_point = + ts_point_add(new_entry.position.extent, new_tree->padding.extent); + TSPoint old_end_point = ts_point_add(old_start_point, old_tree->size.extent); + TSPoint new_end_point = ts_point_add(new_start_point, new_tree->size.extent); + + // #define NAME(t) (ts_language_symbol_name(language, ((TSTree *)(t))->symbol)) + // printf("At [%-2lu, %-2lu] Compare (%-20s\t [%-2lu, %-2lu] - [%lu, %lu])\tvs\t(%-20s\t [%lu, %lu] - [%lu, %lu])\n", + // position.row, position.column, NAME(old_tree), old_start_point.row, + // old_start_point.column, old_end_point.row, old_end_point.column, + // NAME(new_tree), new_start_point.row, new_start_point.column, + // new_end_point.row, new_end_point.column); + + if (ts_point_lt(position, old_start_point)) { + if (ts_point_lt(position, new_start_point)) { + next_position = ts_point_min(old_start_point, new_start_point); + } else { + is_changed = true; + next_position = old_start_point; + } + } else if (ts_point_lt(position, new_start_point)) { + is_changed = true; + next_position = new_start_point; + } else if (old_start_byte == new_start_byte && + tree_must_eq(old_tree, new_tree)) { + next_position = old_end_point; + } else if (old_tree->symbol == new_tree->symbol) { + if (tree_path_descend(old_path, position)) { + if (!tree_path_descend(new_path, position)) { + tree_path_ascend(old_path, 1); + is_changed = true; + next_position = new_end_point; + } + } else if (tree_path_descend(new_path, position)) { + tree_path_ascend(new_path, 1); + is_changed = true; + next_position = old_end_point; + } else { + next_position = ts_point_min(old_end_point, new_end_point); + } + } else { + is_changed = true; + next_position = ts_point_min(old_end_point, new_end_point); + } + + bool at_old_end = ts_point_lte(old_end_point, next_position); + bool at_new_end = ts_point_lte(new_end_point, next_position); + + if (at_new_end && at_old_end) { + size_t old_ascend_count = tree_path_advance(old_path); + size_t new_ascend_count = tree_path_advance(new_path); + if (old_ascend_count > new_ascend_count) { + tree_path_ascend(new_path, old_ascend_count - new_ascend_count); + } else if (new_ascend_count > old_ascend_count) { + tree_path_ascend(old_path, new_ascend_count - old_ascend_count); + } + } else if (at_new_end) { + size_t ascend_count = tree_path_advance(new_path); + tree_path_ascend(old_path, ascend_count); + } else if (at_old_end) { + size_t ascend_count = tree_path_advance(old_path); + tree_path_ascend(new_path, ascend_count); + } + + if (is_changed) range_array_add(&results, position, next_position); + position = next_position; + } + + *ranges = results.contents; + *range_count = results.size; + return true; +} + +#ifdef __cplusplus +} +#endif + +#endif // RUNTIME_TREE_H_