@adecore/editor-react 0.31.12 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AnchoredPopup.js +73 -19
- package/dist/AttributionCard.js +162 -4
- package/dist/BaselineStatus.js +62 -8
- package/dist/CallHierarchyPanel.js +977 -60
- package/dist/ChangeReview.js +76 -25
- package/dist/CodeAuthorsCard.js +314 -14
- package/dist/CompletionPopup.js +490 -83
- package/dist/DiffView.js +548 -181
- package/dist/EditorContextMenu.js +352 -34
- package/dist/EditorView.js +276 -99
- package/dist/FindReplace.js +525 -67
- package/dist/HoverCard.js +378 -38
- package/dist/HoverSections.js +367 -56
- package/dist/LanguagePopups.js +95 -34
- package/dist/Markdown.js +41 -6
- package/dist/PanelResizeHandle.js +199 -66
- package/dist/PathText.js +49 -7
- package/dist/PeekPanel.js +675 -72
- package/dist/PickPopup.js +304 -34
- package/dist/RenameCard.js +679 -85
- package/dist/RenderedDocs.js +329 -58
- package/dist/SignatureCard.js +91 -7
- package/dist/SplitDiffView.js +344 -254
- package/dist/SymbolPicker.js +440 -85
- package/dist/call-hierarchy-model.js +102 -68
- package/dist/call-hierarchy.js +458 -359
- package/dist/code-actions-model.js +88 -76
- package/dist/code-actions.js +372 -283
- package/dist/code-authors.js +64 -55
- package/dist/code-vision-model.js +134 -127
- package/dist/code-vision.js +224 -206
- package/dist/completion-call.js +94 -67
- package/dist/completion-model.js +334 -244
- package/dist/completion.js +840 -649
- package/dist/conflict-model.js +35 -29
- package/dist/context-menu-rows.js +42 -17
- package/dist/context-menu.js +64 -46
- package/dist/definition-link.js +88 -85
- package/dist/diagnostics-model.js +74 -55
- package/dist/diagnostics.js +121 -100
- package/dist/diff-expansion.js +38 -35
- package/dist/diff-overlays.js +144 -22
- package/dist/diff-syntax.js +65 -42
- package/dist/diff-wordmarks.js +26 -23
- package/dist/doc-comment-model.js +265 -216
- package/dist/editor-language.js +177 -152
- package/dist/error-message.js +2 -2
- package/dist/find-query.js +49 -36
- package/dist/folding.js +81 -62
- package/dist/format-on-type.js +86 -67
- package/dist/highlight-layers.js +19 -20
- package/dist/highlights.js +105 -83
- package/dist/history.js +44 -38
- package/dist/holder.js +18 -18
- package/dist/host-types.js +1 -1
- package/dist/hover-content.js +167 -129
- package/dist/hover.js +285 -245
- package/dist/index.js +10 -10
- package/dist/inlay-hints.js +369 -324
- package/dist/key-priority.js +34 -31
- package/dist/language-ids.js +45 -42
- package/dist/line-edits.js +74 -28
- package/dist/line-text.js +18 -3
- package/dist/locales/en.json +38 -38
- package/dist/locales/nl.json +41 -41
- package/dist/models.js +1 -1
- package/dist/navigation-history.js +40 -41
- package/dist/navigation.js +141 -123
- package/dist/panel-size.js +8 -8
- package/dist/patch-decorations.js +236 -160
- package/dist/patch-layout.js +331 -262
- package/dist/paths.js +3 -3
- package/dist/peek-model.js +86 -69
- package/dist/peek.js +254 -192
- package/dist/pick.js +164 -157
- package/dist/popup-focus.js +5 -5
- package/dist/popup-placement.js +36 -21
- package/dist/popups.js +13 -13
- package/dist/project-language.js +228 -211
- package/dist/project-problems.js +81 -69
- package/dist/proposal-model.js +163 -126
- package/dist/recent-choices.js +25 -25
- package/dist/refresher.js +44 -49
- package/dist/rename-model.js +113 -113
- package/dist/rename.js +321 -233
- package/dist/rendered-docs.d.ts +4 -2
- package/dist/rendered-docs.js +384 -318
- package/dist/rendering-context.js +5 -3
- package/dist/rendering.js +22 -4
- package/dist/review-group.js +42 -39
- package/dist/row-host.d.ts +4 -2
- package/dist/row-host.js +90 -78
- package/dist/selection-ranges.js +21 -17
- package/dist/semantic-delta.js +22 -19
- package/dist/semantic-model.js +86 -73
- package/dist/semantic-tokens.js +201 -162
- package/dist/shortcut-keys.js +16 -10
- package/dist/signature-model.js +34 -28
- package/dist/signature.js +177 -129
- package/dist/snippet-field-transforms.js +118 -106
- package/dist/snippet-indent.js +48 -43
- package/dist/snippet-range-order.js +11 -11
- package/dist/snippet-session.js +703 -667
- package/dist/snippet-transform-client.js +59 -59
- package/dist/snippet-transform-format.js +285 -263
- package/dist/snippet-transform-protocol.js +1 -1
- package/dist/snippet-transform-queue.js +163 -153
- package/dist/snippet-transform-worker.js +42 -35
- package/dist/snippet-variable-names.js +1 -36
- package/dist/snippet-variables.js +53 -63
- package/dist/snippet.js +477 -405
- package/dist/split-alignment.js +47 -35
- package/dist/split-scroll.js +42 -40
- package/dist/symbol-links.js +33 -25
- package/dist/symbol-picker-model.js +126 -116
- package/dist/symbol-picker.js +98 -59
- package/dist/symbols.js +117 -88
- package/dist/testing.js +248 -165
- package/dist/timers.js +35 -30
- package/dist/use-panel-body.js +49 -8
- package/dist/use-problem-counts.js +29 -15
- package/dist/view-state.js +54 -33
- package/dist/word-diff.js +18 -18
- package/dist/workspace-edit.js +300 -249
- package/package.json +6 -6
- package/src/CallHierarchyPanel.tsx +2 -2
- package/src/DiffView.tsx +3 -3
- package/src/FindReplace.tsx +2 -2
- package/src/LanguagePopups.tsx +2 -0
- package/src/PeekPanel.tsx +3 -3
- package/src/RenderedDocs.tsx +9 -10
- package/src/SymbolPicker.tsx +2 -2
- package/src/diff-overlays.tsx +6 -4
- package/src/locales/en.json +38 -38
- package/src/locales/nl.json +41 -41
- package/src/rendered-docs.ts +14 -3
- package/src/row-host.ts +14 -3
package/dist/snippet.js
CHANGED
|
@@ -6,444 +6,516 @@ const MAX_SNIPPET_NODES = 10_000;
|
|
|
6
6
|
const MAX_SNIPPET_WORK = 50_000;
|
|
7
7
|
const MAX_SNIPPET_RANGES = 1_000;
|
|
8
8
|
const MAX_SNIPPET_DEPTH = 64;
|
|
9
|
-
class SnippetLimitError extends Error {
|
|
10
|
-
}
|
|
11
|
-
class MalformedSnippetError extends Error {
|
|
12
|
-
}
|
|
9
|
+
class SnippetLimitError extends Error {}
|
|
10
|
+
class MalformedSnippetError extends Error {}
|
|
13
11
|
class SnippetParser {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
12
|
+
at = 0;
|
|
13
|
+
nodes = 0;
|
|
14
|
+
depth = 0;
|
|
15
|
+
name = /(?:\d+|[A-Za-z_]\w*)/y;
|
|
16
|
+
source;
|
|
17
|
+
constructor(source) {
|
|
18
|
+
this.source = source;
|
|
19
|
+
}
|
|
20
|
+
parse() {
|
|
21
|
+
return this.sequence(false);
|
|
22
|
+
}
|
|
23
|
+
sequence(nested) {
|
|
24
|
+
if (++this.depth > MAX_SNIPPET_DEPTH) {
|
|
25
|
+
throw new SnippetLimitError();
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (node === null) {
|
|
46
|
-
text += '$';
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
flush();
|
|
50
|
-
this.push(nodes, node);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
text += character;
|
|
55
|
-
this.at++;
|
|
56
|
-
}
|
|
27
|
+
const nodes = [];
|
|
28
|
+
let text = '';
|
|
29
|
+
const flush = () => {
|
|
30
|
+
if (text !== '') {
|
|
31
|
+
this.push(nodes, {
|
|
32
|
+
kind: 'text',
|
|
33
|
+
text
|
|
34
|
+
});
|
|
35
|
+
text = '';
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
while (this.at < this.source.length && !(nested && this.source[this.at] === '}')) {
|
|
39
|
+
const character = this.source[this.at];
|
|
40
|
+
if (character === '\\' && /[\\$}]/.test(this.source[this.at + 1] ?? '')) {
|
|
41
|
+
text += this.source[this.at + 1];
|
|
42
|
+
this.at += 2;
|
|
43
|
+
} else if (character === '$') {
|
|
44
|
+
const node = this.dollar();
|
|
45
|
+
if (node === null) {
|
|
46
|
+
text += '$';
|
|
47
|
+
} else {
|
|
48
|
+
flush();
|
|
49
|
+
this.push(nodes, node);
|
|
57
50
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
} else {
|
|
52
|
+
text += character;
|
|
53
|
+
this.at++;
|
|
54
|
+
}
|
|
61
55
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
flush();
|
|
57
|
+
this.depth--;
|
|
58
|
+
return nodes;
|
|
59
|
+
}
|
|
60
|
+
push(nodes, node) {
|
|
61
|
+
if (++this.nodes > MAX_SNIPPET_NODES) {
|
|
62
|
+
throw new SnippetLimitError();
|
|
67
63
|
}
|
|
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
|
-
|
|
105
|
-
|
|
64
|
+
nodes.push(node);
|
|
65
|
+
}
|
|
66
|
+
dollar() {
|
|
67
|
+
const start = this.at++;
|
|
68
|
+
const brace = this.source[this.at] === '{';
|
|
69
|
+
if (brace) {
|
|
70
|
+
this.at++;
|
|
71
|
+
}
|
|
72
|
+
this.name.lastIndex = this.at;
|
|
73
|
+
const name = this.name.exec(this.source)?.[0];
|
|
74
|
+
if (name === undefined) {
|
|
75
|
+
this.at = start + 1;
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const index = /^\d+$/.test(name) ? Number(name) : null;
|
|
79
|
+
if (index !== null && !Number.isSafeInteger(index)) {
|
|
80
|
+
this.at = start + 1;
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
this.at += name.length;
|
|
84
|
+
const field = () => ({
|
|
85
|
+
kind: 'field',
|
|
86
|
+
index: index
|
|
87
|
+
});
|
|
88
|
+
if (!brace) {
|
|
89
|
+
return index === null ? {
|
|
90
|
+
kind: 'variable',
|
|
91
|
+
name
|
|
92
|
+
} : field();
|
|
93
|
+
}
|
|
94
|
+
const next = this.source[this.at];
|
|
95
|
+
if (next === '}') {
|
|
96
|
+
this.at++;
|
|
97
|
+
return index === null ? {
|
|
98
|
+
kind: 'variable',
|
|
99
|
+
name
|
|
100
|
+
} : field();
|
|
101
|
+
}
|
|
102
|
+
if (next === ':') {
|
|
103
|
+
this.at++;
|
|
104
|
+
const body = this.sequence(true);
|
|
105
|
+
if (this.source[this.at] === '}') {
|
|
106
|
+
this.at++;
|
|
107
|
+
}
|
|
108
|
+
return index === null ? {
|
|
109
|
+
kind: 'variable',
|
|
110
|
+
name,
|
|
111
|
+
body
|
|
112
|
+
} : {
|
|
113
|
+
...field(),
|
|
114
|
+
body
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (next === '|' && index !== null) {
|
|
118
|
+
this.at++;
|
|
119
|
+
return {
|
|
120
|
+
...field(),
|
|
121
|
+
choices: this.choices()
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (next === '/') {
|
|
125
|
+
try {
|
|
126
|
+
const {
|
|
127
|
+
end,
|
|
128
|
+
...transform
|
|
129
|
+
} = scanSnippetTransform(this.source, this.at);
|
|
130
|
+
this.at = end;
|
|
131
|
+
return index === null ? {
|
|
132
|
+
kind: 'variable',
|
|
133
|
+
name,
|
|
134
|
+
transform
|
|
135
|
+
} : {
|
|
136
|
+
...field(),
|
|
137
|
+
transform
|
|
138
|
+
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error instanceof RangeError) {
|
|
141
|
+
throw new SnippetLimitError();
|
|
106
142
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
const { end, ...transform } = scanSnippetTransform(this.source, this.at);
|
|
110
|
-
this.at = end;
|
|
111
|
-
return index === null ? { kind: 'variable', name, transform } : { ...field(), transform };
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
if (error instanceof RangeError) {
|
|
115
|
-
throw new SnippetLimitError();
|
|
116
|
-
}
|
|
117
|
-
if (error instanceof SyntaxError) {
|
|
118
|
-
throw new MalformedSnippetError();
|
|
119
|
-
}
|
|
120
|
-
throw error;
|
|
121
|
-
}
|
|
143
|
+
if (error instanceof SyntaxError) {
|
|
144
|
+
throw new MalformedSnippetError();
|
|
122
145
|
}
|
|
123
|
-
|
|
124
|
-
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
125
148
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
values[values.length - 1] += character;
|
|
141
|
-
}
|
|
149
|
+
this.at = start + 1;
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
choices() {
|
|
153
|
+
const values = [''];
|
|
154
|
+
while (this.at < this.source.length && !(this.source[this.at] === '|' && this.source[this.at + 1] === '}')) {
|
|
155
|
+
const character = this.source[this.at++];
|
|
156
|
+
if (character === '\\' && /[\\,|]/.test(this.source[this.at] ?? '')) {
|
|
157
|
+
values[values.length - 1] += this.source[this.at++];
|
|
158
|
+
} else if (character === ',') {
|
|
159
|
+
if (values.length >= MAX_SNIPPET_NODES) {
|
|
160
|
+
throw new SnippetLimitError();
|
|
142
161
|
}
|
|
143
|
-
|
|
144
|
-
|
|
162
|
+
values.push('');
|
|
163
|
+
} else {
|
|
164
|
+
values[values.length - 1] += character;
|
|
165
|
+
}
|
|
145
166
|
}
|
|
167
|
+
this.at = Math.min(this.source.length, this.at + 2);
|
|
168
|
+
return values;
|
|
169
|
+
}
|
|
146
170
|
}
|
|
147
171
|
function renderSnippet(nodes, variableTransforms) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
known.choices === undefined &&
|
|
156
|
-
(node.body !== undefined || node.choices !== undefined || (known.transform !== undefined && node.transform === undefined)))) {
|
|
157
|
-
definitions.set(node.index, node);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (node.kind !== 'text' && node.body !== undefined) {
|
|
161
|
-
collect(node.body);
|
|
162
|
-
}
|
|
172
|
+
const definitions = new Map();
|
|
173
|
+
const collect = nodes => {
|
|
174
|
+
for (const node of nodes) {
|
|
175
|
+
if (node.kind === 'field') {
|
|
176
|
+
const known = definitions.get(node.index);
|
|
177
|
+
if (known === undefined || known.body === undefined && known.choices === undefined && (node.body !== undefined || node.choices !== undefined || known.transform !== undefined && node.transform === undefined)) {
|
|
178
|
+
definitions.set(node.index, node);
|
|
163
179
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
}
|
|
181
|
+
if (node.kind !== 'text' && node.body !== undefined) {
|
|
182
|
+
collect(node.body);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
collect(nodes);
|
|
187
|
+
const fields = new Map();
|
|
188
|
+
const stops = [];
|
|
189
|
+
const transforms = [];
|
|
190
|
+
let text = '';
|
|
191
|
+
let work = 0;
|
|
192
|
+
let ranges = 0;
|
|
193
|
+
let occurrence = 0;
|
|
194
|
+
let tailEvent = 0;
|
|
195
|
+
let tailOffset = -1;
|
|
196
|
+
const recordTail = range => {
|
|
197
|
+
if (range.start === range.end || range.tail === true) {
|
|
198
|
+
tailEvent++;
|
|
199
|
+
tailOffset = range.end;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const append = value => {
|
|
203
|
+
if (text.length + value.length > MAX_SNIPPET_TEXT) {
|
|
204
|
+
throw new SnippetLimitError();
|
|
205
|
+
}
|
|
206
|
+
text += value;
|
|
207
|
+
};
|
|
208
|
+
const render = (nodes, linked, parents, visiting) => {
|
|
209
|
+
if (parents.length > MAX_SNIPPET_DEPTH) {
|
|
210
|
+
throw new SnippetLimitError();
|
|
211
|
+
}
|
|
212
|
+
for (const node of nodes) {
|
|
213
|
+
if (++work > MAX_SNIPPET_WORK) {
|
|
214
|
+
throw new SnippetLimitError();
|
|
215
|
+
}
|
|
216
|
+
const order = occurrence++;
|
|
217
|
+
if (node.kind === 'text') {
|
|
218
|
+
const start = text.length;
|
|
219
|
+
const value = node.transform === undefined || variableTransforms === undefined ? node.text : variableTransforms[transforms.length];
|
|
220
|
+
if (typeof value !== 'string') {
|
|
221
|
+
throw new RangeError('The variable transform count does not match the snippet.');
|
|
179
222
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
223
|
+
append(value);
|
|
224
|
+
if (node.transform !== undefined) {
|
|
225
|
+
if (++ranges > MAX_SNIPPET_RANGES) {
|
|
183
226
|
throw new SnippetLimitError();
|
|
227
|
+
}
|
|
228
|
+
const range = {
|
|
229
|
+
start,
|
|
230
|
+
end: text.length,
|
|
231
|
+
transform: node.transform,
|
|
232
|
+
...(parents.length === 0 ? {} : {
|
|
233
|
+
parents: [...parents]
|
|
234
|
+
})
|
|
235
|
+
};
|
|
236
|
+
withSnippetOrder(range, order);
|
|
237
|
+
transforms.push(range);
|
|
238
|
+
recordTail(range);
|
|
184
239
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (node.kind === 'variable') {
|
|
243
|
+
render(node.body ?? [], linked, parents, visiting);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (++ranges > MAX_SNIPPET_RANGES) {
|
|
247
|
+
throw new SnippetLimitError();
|
|
248
|
+
}
|
|
249
|
+
const definition = definitions.get(node.index);
|
|
250
|
+
const from = text.length;
|
|
251
|
+
const beforeTail = tailEvent;
|
|
252
|
+
if (!visiting.has(node.index)) {
|
|
253
|
+
if (definition.choices !== undefined) {
|
|
254
|
+
append(definition.choices[0] ?? '');
|
|
255
|
+
} else {
|
|
256
|
+
render(definition.body ?? [], linked || node !== definition, [...parents, node.index], new Set([...visiting, node.index]));
|
|
190
257
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const definition = definitions.get(node.index);
|
|
222
|
-
const from = text.length;
|
|
223
|
-
const beforeTail = tailEvent;
|
|
224
|
-
if (!visiting.has(node.index)) {
|
|
225
|
-
if (definition.choices !== undefined) {
|
|
226
|
-
append(definition.choices[0] ?? '');
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
render(definition.body ?? [], linked || node !== definition, [...parents, node.index], new Set([...visiting, node.index]));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
const range = {
|
|
233
|
-
start: from,
|
|
234
|
-
end: text.length,
|
|
235
|
-
...(parents.length === 0 ? {} : { parents: [...parents] }),
|
|
236
|
-
...(node.transform === undefined ? {} : { transform: node.transform }),
|
|
237
|
-
...(tailEvent !== beforeTail && tailOffset === text.length ? { tail: true } : {})
|
|
238
|
-
};
|
|
239
|
-
withSnippetOrder(range, order);
|
|
240
|
-
recordTail(range);
|
|
241
|
-
const field = fields.get(node.index) ?? {
|
|
242
|
-
index: node.index,
|
|
243
|
-
ranges: [],
|
|
244
|
-
linked: [],
|
|
245
|
-
primary: 0,
|
|
246
|
-
parents: new Set(),
|
|
247
|
-
choices: definition.choices
|
|
248
|
-
};
|
|
249
|
-
parents.filter((parent) => parent !== node.index).forEach((parent) => field.parents.add(parent));
|
|
250
|
-
if (linked) {
|
|
251
|
-
field.linked.push(range);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
if (node === definition) {
|
|
255
|
-
field.primary = field.ranges.length;
|
|
256
|
-
}
|
|
257
|
-
field.ranges.push(range);
|
|
258
|
-
stops.push(withSnippetOrder({
|
|
259
|
-
index: node.index,
|
|
260
|
-
start: range.start,
|
|
261
|
-
end: range.end,
|
|
262
|
-
...(node.transform === undefined ? {} : { transform: node.transform }),
|
|
263
|
-
...(range.tail === undefined ? {} : { tail: range.tail })
|
|
264
|
-
}, order));
|
|
265
|
-
}
|
|
266
|
-
fields.set(node.index, field);
|
|
258
|
+
}
|
|
259
|
+
const range = {
|
|
260
|
+
start: from,
|
|
261
|
+
end: text.length,
|
|
262
|
+
...(parents.length === 0 ? {} : {
|
|
263
|
+
parents: [...parents]
|
|
264
|
+
}),
|
|
265
|
+
...(node.transform === undefined ? {} : {
|
|
266
|
+
transform: node.transform
|
|
267
|
+
}),
|
|
268
|
+
...(tailEvent !== beforeTail && tailOffset === text.length ? {
|
|
269
|
+
tail: true
|
|
270
|
+
} : {})
|
|
271
|
+
};
|
|
272
|
+
withSnippetOrder(range, order);
|
|
273
|
+
recordTail(range);
|
|
274
|
+
const field = fields.get(node.index) ?? {
|
|
275
|
+
index: node.index,
|
|
276
|
+
ranges: [],
|
|
277
|
+
linked: [],
|
|
278
|
+
primary: 0,
|
|
279
|
+
parents: new Set(),
|
|
280
|
+
choices: definition.choices
|
|
281
|
+
};
|
|
282
|
+
parents.filter(parent => parent !== node.index).forEach(parent => field.parents.add(parent));
|
|
283
|
+
if (linked) {
|
|
284
|
+
field.linked.push(range);
|
|
285
|
+
} else {
|
|
286
|
+
if (node === definition) {
|
|
287
|
+
field.primary = field.ranges.length;
|
|
267
288
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
289
|
+
field.ranges.push(range);
|
|
290
|
+
stops.push(withSnippetOrder({
|
|
291
|
+
index: node.index,
|
|
292
|
+
start: range.start,
|
|
293
|
+
end: range.end,
|
|
294
|
+
...(node.transform === undefined ? {} : {
|
|
295
|
+
transform: node.transform
|
|
296
|
+
}),
|
|
297
|
+
...(range.tail === undefined ? {} : {
|
|
298
|
+
tail: range.tail
|
|
299
|
+
})
|
|
300
|
+
}, order));
|
|
301
|
+
}
|
|
302
|
+
fields.set(node.index, field);
|
|
272
303
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
304
|
+
};
|
|
305
|
+
render(nodes, false, [], new Set());
|
|
306
|
+
if (variableTransforms !== undefined && variableTransforms.length !== transforms.length) {
|
|
307
|
+
throw new RangeError('The variable transform count does not match the snippet.');
|
|
308
|
+
}
|
|
309
|
+
stops.sort((left, right) => left.start - right.start || right.end - left.end);
|
|
310
|
+
return {
|
|
311
|
+
text,
|
|
312
|
+
stops,
|
|
313
|
+
...(transforms.length === 0 ? {} : {
|
|
314
|
+
transforms
|
|
315
|
+
}),
|
|
316
|
+
fields: [...fields.values()].filter(field => field.ranges.length > 0).map(field => ({
|
|
317
|
+
index: field.index,
|
|
318
|
+
ranges: field.ranges,
|
|
319
|
+
primary: field.primary,
|
|
320
|
+
...(field.linked.length === 0 ? {} : {
|
|
321
|
+
linked: field.linked
|
|
322
|
+
}),
|
|
323
|
+
...(field.parents.size === 0 ? {} : {
|
|
324
|
+
parents: [...field.parents]
|
|
325
|
+
}),
|
|
326
|
+
...(field.choices === undefined ? {} : {
|
|
327
|
+
choices: field.choices
|
|
328
|
+
})
|
|
329
|
+
}))
|
|
330
|
+
};
|
|
289
331
|
}
|
|
290
332
|
function variableIndices(nodes) {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}));
|
|
333
|
+
let highest = 0;
|
|
334
|
+
const names = new Set();
|
|
335
|
+
const scan = nodes => {
|
|
336
|
+
for (const node of nodes) {
|
|
337
|
+
if (node.kind === 'field') {
|
|
338
|
+
highest = Math.max(highest, node.index);
|
|
339
|
+
} else if (node.kind === 'variable' && !SNIPPET_VARIABLES.has(node.name)) {
|
|
340
|
+
names.add(node.name);
|
|
341
|
+
}
|
|
342
|
+
if (node.kind !== 'text' && node.body !== undefined) {
|
|
343
|
+
scan(node.body);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
scan(nodes);
|
|
348
|
+
return new Map([...names].map(name => {
|
|
349
|
+
if (!Number.isSafeInteger(++highest)) {
|
|
350
|
+
throw new SnippetLimitError();
|
|
351
|
+
}
|
|
352
|
+
return [name, highest];
|
|
353
|
+
}));
|
|
313
354
|
}
|
|
314
355
|
function resolveVariables(nodes, indices, resolve) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
if (node.kind !== 'text' && node.body !== undefined) {
|
|
345
|
-
collect(node.body);
|
|
346
|
-
}
|
|
356
|
+
const unknown = new Map();
|
|
357
|
+
const values = new Map();
|
|
358
|
+
const valueOf = name => {
|
|
359
|
+
if (!values.has(name)) {
|
|
360
|
+
values.set(name, resolve?.(name));
|
|
361
|
+
}
|
|
362
|
+
return values.get(name);
|
|
363
|
+
};
|
|
364
|
+
const collect = nodes => {
|
|
365
|
+
for (const node of nodes) {
|
|
366
|
+
if (node.kind === 'variable' && valueOf(node.name) === undefined && !SNIPPET_VARIABLES.has(node.name)) {
|
|
367
|
+
const previous = unknown.get(node.name);
|
|
368
|
+
if (previous === undefined) {
|
|
369
|
+
unknown.set(node.name, {
|
|
370
|
+
index: indices.get(node.name),
|
|
371
|
+
body: node.body ?? [{
|
|
372
|
+
kind: 'text',
|
|
373
|
+
text: node.name
|
|
374
|
+
}],
|
|
375
|
+
defaulted: node.body !== undefined,
|
|
376
|
+
definition: node
|
|
377
|
+
});
|
|
378
|
+
} else if (node.body !== undefined && !previous.defaulted) {
|
|
379
|
+
previous.body = node.body;
|
|
380
|
+
previous.defaulted = true;
|
|
381
|
+
previous.definition = node;
|
|
382
|
+
} else if (!previous.defaulted && node.transform === undefined && previous.definition.transform !== undefined) {
|
|
383
|
+
previous.definition = node;
|
|
347
384
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
385
|
+
}
|
|
386
|
+
if (node.kind !== 'text' && node.body !== undefined) {
|
|
387
|
+
collect(node.body);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
collect(nodes);
|
|
392
|
+
// Resolved empty variables retain their defaults without adding a navigable field.
|
|
393
|
+
let work = 0;
|
|
394
|
+
const normalize = (nodes, visiting, depth = 0) => {
|
|
395
|
+
if (depth > MAX_SNIPPET_DEPTH) {
|
|
396
|
+
throw new SnippetLimitError();
|
|
397
|
+
}
|
|
398
|
+
return nodes.flatMap(node => {
|
|
399
|
+
if (++work > MAX_SNIPPET_WORK) {
|
|
400
|
+
throw new SnippetLimitError();
|
|
401
|
+
}
|
|
402
|
+
if (node.kind === 'variable' && !unknown.has(node.name)) {
|
|
403
|
+
const value = valueOf(node.name);
|
|
404
|
+
if (node.transform !== undefined) {
|
|
405
|
+
return [{
|
|
406
|
+
kind: 'text',
|
|
407
|
+
text: value ?? '',
|
|
408
|
+
transform: node.transform
|
|
409
|
+
}];
|
|
355
410
|
}
|
|
356
|
-
return
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return normalize(nodes, new Set());
|
|
411
|
+
return value !== undefined && value !== '' ? [{
|
|
412
|
+
kind: 'text',
|
|
413
|
+
text: value
|
|
414
|
+
}] : normalize(node.body ?? [], visiting, depth + 1);
|
|
415
|
+
}
|
|
416
|
+
if (node.kind === 'field') {
|
|
417
|
+
return [{
|
|
418
|
+
...node,
|
|
419
|
+
...(node.body === undefined ? {} : {
|
|
420
|
+
body: normalize(node.body, visiting, depth + 1)
|
|
421
|
+
})
|
|
422
|
+
}];
|
|
423
|
+
}
|
|
424
|
+
if (node.kind === 'variable') {
|
|
425
|
+
const field = unknown.get(node.name);
|
|
426
|
+
return [{
|
|
427
|
+
kind: 'field',
|
|
428
|
+
index: field.index,
|
|
429
|
+
...(node.transform === undefined ? {} : {
|
|
430
|
+
transform: node.transform
|
|
431
|
+
}),
|
|
432
|
+
...(node !== field.definition ? {} : {
|
|
433
|
+
body: visiting.has(node.name) ? [] : normalize(field.body, new Set([...visiting, node.name]), depth + 1)
|
|
434
|
+
})
|
|
435
|
+
}];
|
|
436
|
+
}
|
|
437
|
+
return [node];
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
return normalize(nodes, new Set());
|
|
387
441
|
}
|
|
388
442
|
export function compileSnippet(source) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
443
|
+
let nodes = null;
|
|
444
|
+
let indices = new Map();
|
|
445
|
+
if (source.length <= MAX_SNIPPET_TEXT) {
|
|
446
|
+
try {
|
|
447
|
+
nodes = new SnippetParser(source).parse();
|
|
448
|
+
indices = variableIndices(nodes);
|
|
449
|
+
} catch (error) {
|
|
450
|
+
if (error instanceof MalformedSnippetError) {
|
|
451
|
+
return {
|
|
452
|
+
source,
|
|
453
|
+
render: () => ({
|
|
454
|
+
text: source,
|
|
455
|
+
stops: []
|
|
456
|
+
})
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
if (!(error instanceof SnippetLimitError)) {
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
nodes = null;
|
|
405
463
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
source,
|
|
467
|
+
render: (resolve, variableTransforms) => {
|
|
468
|
+
if (nodes === null) {
|
|
469
|
+
return {
|
|
470
|
+
text: source,
|
|
471
|
+
stops: [],
|
|
472
|
+
limited: true
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
try {
|
|
476
|
+
return renderSnippet(resolveVariables(nodes, indices, resolve), variableTransforms);
|
|
477
|
+
} catch (error) {
|
|
478
|
+
if (!(error instanceof SnippetLimitError)) {
|
|
479
|
+
throw error;
|
|
422
480
|
}
|
|
423
|
-
|
|
481
|
+
// Language-server snippets may expand exponentially; retain the original text without a session.
|
|
482
|
+
return {
|
|
483
|
+
text: source,
|
|
484
|
+
stops: [],
|
|
485
|
+
limited: true
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
424
490
|
}
|
|
425
491
|
export function parseSnippet(snippet, resolve) {
|
|
426
|
-
|
|
492
|
+
return compileSnippet(snippet).render(resolve);
|
|
427
493
|
}
|
|
428
494
|
/* One defining occurrence per index, then $0 or the end of the inserted text. */
|
|
429
495
|
export function tabOrder(parsed) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
496
|
+
const first = new Map();
|
|
497
|
+
for (const stop of parsed.stops) {
|
|
498
|
+
if (!first.has(stop.index)) {
|
|
499
|
+
first.set(stop.index, stop);
|
|
435
500
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
501
|
+
}
|
|
502
|
+
for (const field of parsed.fields ?? []) {
|
|
503
|
+
const range = field.ranges[field.primary];
|
|
504
|
+
if (range !== undefined) {
|
|
505
|
+
first.set(field.index, {
|
|
506
|
+
index: field.index,
|
|
507
|
+
start: range.start,
|
|
508
|
+
end: range.end,
|
|
509
|
+
...(range.transform === undefined ? {} : {
|
|
510
|
+
transform: range.transform
|
|
511
|
+
})
|
|
512
|
+
});
|
|
446
513
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
514
|
+
}
|
|
515
|
+
const visited = [...first.values()].filter(stop => stop.index > 0).sort((left, right) => left.index - right.index);
|
|
516
|
+
return [...visited, first.get(0) ?? {
|
|
517
|
+
index: 0,
|
|
518
|
+
start: parsed.text.length,
|
|
519
|
+
end: parsed.text.length
|
|
520
|
+
}];
|
|
521
|
+
}
|