-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathedit_demo.cpp
More file actions
104 lines (88 loc) · 3.48 KB
/
Copy pathedit_demo.cpp
File metadata and controls
104 lines (88 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Incremental parsing. Reparsing after a small edit without redoing the
// whole file.
//
// First tell the old tree what changed using Tree::edit. Then hand that tree
// back to Parser::parse along with the new source. tree-sitter reuses every
// subtree the edit did not touch.
//
// A ts::InputEdit holds three ts::Locations, and each Location pairs a byte
// offset with a Point holding a row and a column.
//
// start where the replaced region begins, in the old coordinates
// oldEnd where that region ended before the edit, in the old coordinates
// newEnd where the replacement ends after the edit, in the new coordinates
//
// Tree::edit shifts the old tree's positions in place, so any Node you
// fetched from that tree beforehand is wrong once the edit is applied. Fetch
// fresh nodes from the tree the reparse hands back.
//
// oldTree.getChangedRanges(newTree) reports differences in structure. It
// compares node types and extents once those extents have been shifted for
// the edit, and it does not compare the text inside a leaf. Both edits below
// rewrite the same one-character value, but only the second one changes a
// node's type, and only the second one is reported. So this tells you
// whether the shape of the tree changed somewhere as opposed to the content
// of leaves.
#include <cstdlib>
#include <print>
#include <string_view>
#include <cpp-tree-sitter.h>
#include <cts/format.h>
extern "C" TSLanguage* tree_sitter_json();
namespace {
// Applies one edit, reparses incrementally, and reports what tree-sitter
// considers structurally different afterwards.
void
reportEdit(ts::Parser& parser, std::string_view label,
std::string_view oldSource, std::string_view newSource,
const ts::InputEdit& edit) {
auto oldTree = parser.parse(oldSource);
if (!oldTree) {
std::println(stderr, "error: {}", oldTree.error());
return;
}
oldTree->edit(edit);
// Passing the edited tree makes this incremental.
auto newTree = parser.parse(newSource, *oldTree);
if (!newTree) {
std::println(stderr, "error: {}", newTree.error());
return;
}
std::println("{}: {} -> {}", label, oldSource, newSource);
std::println(" tree: {}", newTree->getRootNode().getSExpr());
auto changed = oldTree->getChangedRanges(*newTree);
if (changed.empty()) {
std::println(" no structural change");
}
for (const ts::Range& range : changed) {
std::println(" changed: {}", range);
}
}
}
int
main() {
auto parser = ts::Parser::create(tree_sitter_json());
if (!parser) {
std::println(stderr, "error: {}", parser.error());
return EXIT_FAILURE;
}
// 0123456 7
constexpr std::string_view before = R"({"a": 1})";
// Replacing `1` with `42` leaves a `number` where a `number` was, so the
// shape of the tree is unchanged and nothing is reported.
reportEdit(*parser, "same node type", before, R"({"a": 42})",
ts::InputEdit{
.start = {.byte=6, .point={0, 6}},
.oldEnd = {.byte=7, .point={0, 7}},
.newEnd = {.byte=8, .point={0, 8}},
});
// Replacing `1` with `true` swaps a `number` for a `true`. That is a
// change in shape, so this one is reported.
reportEdit(*parser, "new node type ", before, R"({"a": true})",
ts::InputEdit{
.start = {.byte=6, .point={0, 6}},
.oldEnd = {.byte=7, .point={0, 7}},
.newEnd = {.byte=10, .point={0, 10}},
});
return EXIT_SUCCESS;
}