diff --git a/lib/binding_web/binding.c b/lib/binding_web/binding.c index 99e7d8ce..31efeceb 100644 --- a/lib/binding_web/binding.c +++ b/lib/binding_web/binding.c @@ -74,6 +74,20 @@ static TSPoint unmarshal_point(const void **address) { return point; } +static void marshal_range(TSRange *range) { + range->start_byte = byte_to_code_unit(range->start_byte); + range->end_byte = byte_to_code_unit(range->end_byte); + range->start_point.column = byte_to_code_unit(range->start_point.column); + range->end_point.column = byte_to_code_unit(range->end_point.column); +} + +static void unmarshal_range(TSRange *range) { + range->start_byte = code_unit_to_byte(range->start_byte); + range->end_byte = code_unit_to_byte(range->end_byte); + range->start_point.column = code_unit_to_byte(range->start_point.column); + range->end_point.column = code_unit_to_byte(range->end_point.column); +} + static TSInputEdit unmarshal_edit() { TSInputEdit edit; const void **address = TRANSFER_BUFFER; @@ -151,11 +165,7 @@ TSTree *ts_parser_parse_wasm( }; if (range_count) { for (unsigned i = 0; i < range_count; i++) { - TSRange *range = &ranges[i]; - range->start_byte = code_unit_to_byte(range->start_byte); - range->end_byte = code_unit_to_byte(range->end_byte); - range->start_point.column = code_unit_to_byte(range->start_point.column); - range->end_point.column = code_unit_to_byte(range->end_point.column); + unmarshal_range(&ranges[i]); } ts_parser_set_included_ranges(self, ranges, range_count); free(ranges); @@ -178,6 +188,16 @@ void ts_tree_edit_wasm(TSTree *tree) { ts_tree_edit(tree, &edit); } +void ts_tree_get_changed_ranges_wasm(TSTree *tree, TSTree *other) { + unsigned range_count; + TSRange *ranges = ts_tree_get_changed_ranges(tree, other, &range_count); + for (unsigned i = 0; i < range_count; i++) { + marshal_range(&ranges[i]); + } + TRANSFER_BUFFER[0] = (const void *)range_count; + TRANSFER_BUFFER[1] = (const void *)ranges; +} + /************************/ /* Section - TreeCursor */ /************************/ diff --git a/lib/binding_web/binding.js b/lib/binding_web/binding.js index 89fcfa91..bbe3fe81 100644 --- a/lib/binding_web/binding.js +++ b/lib/binding_web/binding.js @@ -175,6 +175,26 @@ class Tree { walk() { return this.rootNode.walk(); } + + getChangedRanges(other) { + if (other.constructor !== Tree) { + throw new TypeError('Argument must be a Tree'); + } + + C._ts_tree_get_changed_ranges_wasm(this[0], other[0]); + const count = getValue(TRANSFER_BUFFER, 'i32'); + const buffer = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32'); + const result = new Array(count); + if (count > 0) { + let address = buffer; + for (let i = 0; i < count; i++) { + result[i] = unmarshalRange(address); + address += SIZE_OF_RANGE; + } + C._free(buffer); + } + return result; + } } class Node { diff --git a/lib/binding_web/exports.json b/lib/binding_web/exports.json index ce95bbd4..456feb19 100644 --- a/lib/binding_web/exports.json +++ b/lib/binding_web/exports.json @@ -81,5 +81,6 @@ "_ts_tree_cursor_start_position_wasm", "_ts_tree_delete", "_ts_tree_edit_wasm", + "_ts_tree_get_changed_ranges_wasm", "_ts_tree_root_node_wasm" ] diff --git a/lib/binding_web/test/tree-test.js b/lib/binding_web/test/tree-test.js index 648829ca..bcdbf5b5 100644 --- a/lib/binding_web/test/tree-test.js +++ b/lib/binding_web/test/tree-test.js @@ -81,6 +81,54 @@ describe("Tree", () => { }); }); + describe(".getChangedRanges(previous)", () => { + it("reports the ranges of text whose syntactic meaning has changed", () => { + let sourceCode = "abcdefg + hij"; + tree = parser.parse(sourceCode); + + assert.equal( + tree.rootNode.toString(), + "(program (expression_statement (binary_expression (identifier) (identifier))))" + ); + + sourceCode = "abc + defg + hij"; + tree.edit({ + startIndex: 2, + oldEndIndex: 2, + newEndIndex: 5, + startPosition: { row: 0, column: 2 }, + oldEndPosition: { row: 0, column: 2 }, + newEndPosition: { row: 0, column: 5 } + }); + + const tree2 = parser.parse(sourceCode, tree); + assert.equal( + tree2.rootNode.toString(), + "(program (expression_statement (binary_expression (binary_expression (identifier) (identifier)) (identifier))))" + ); + + const ranges = tree.getChangedRanges(tree2); + assert.deepEqual(ranges, [ + { + startIndex: 0, + endIndex: "abc + defg".length, + startPosition: { row: 0, column: 0 }, + endPosition: { row: 0, column: "abc + defg".length } + } + ]); + + tree2.delete(); + }); + + it('throws an exception if the argument is not a tree', () => { + tree = parser.parse("abcdefg + hij"); + + assert.throws(() => { + tree.getChangedRanges({}); + }, /Argument must be a Tree/); + }) + }); + describe(".walk()", () => { let cursor