@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/call-hierarchy.js
CHANGED
|
@@ -19,381 +19,480 @@ const OWNER = 'call-hierarchy';
|
|
|
19
19
|
* shortcut that opened the tree switches between callers and callees. Typing closes it.
|
|
20
20
|
*/
|
|
21
21
|
export class CallHierarchyFeature {
|
|
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
|
-
try {
|
|
82
|
-
items = await project.service.prepareCallHierarchy(uri, position, { signal: this.controller.signal });
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
if (epoch === this.epoch && !(error instanceof StaleResultError)) {
|
|
86
|
-
this.tell(this.say('failed', { message: messageOf(error) }));
|
|
87
|
-
}
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (epoch !== this.epoch) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (items === null || items.length === 0) {
|
|
94
|
-
this.tell(this.say('none'));
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
this.language.peek.close();
|
|
98
|
-
this.prepared = items;
|
|
99
|
-
this.direction = direction;
|
|
100
|
-
this.seed();
|
|
101
|
-
const active = this.roots[0];
|
|
102
|
-
this.language.popups.setState({
|
|
103
|
-
callHierarchy: { direction, container: null, name: items[0].name, rows: rowsOf(this.nodes, this.roots), active, site: 0, sites: 0, preview: null }
|
|
104
|
-
});
|
|
105
|
-
this.select(active);
|
|
106
|
-
// The editor draws a row once per id, so a tree opened over another needs an id of its own to get a container.
|
|
107
|
-
editor.setWidgets([{ id: `call-hierarchy-${epoch}`, line: position.line, height: CALL_HIERARCHY_HEIGHT, render: (container) => this.mounted(container) }], OWNER);
|
|
108
|
-
editor.focus();
|
|
109
|
-
for (const root of this.roots) {
|
|
110
|
-
void this.load(root);
|
|
111
|
-
}
|
|
22
|
+
language;
|
|
23
|
+
timers;
|
|
24
|
+
nodes = new Map();
|
|
25
|
+
roots = [];
|
|
26
|
+
prepared = [];
|
|
27
|
+
direction = 'incoming';
|
|
28
|
+
controller = new AbortController();
|
|
29
|
+
/* Raised whenever the tree starts over or closes, so an answer for the tree that was never lands in the one that is. */
|
|
30
|
+
epoch = 0;
|
|
31
|
+
previewEpoch = 0;
|
|
32
|
+
texts = new Map();
|
|
33
|
+
constructor(language, timers = realTimers) {
|
|
34
|
+
this.language = language;
|
|
35
|
+
this.timers = timers;
|
|
36
|
+
const {
|
|
37
|
+
editor
|
|
38
|
+
} = language;
|
|
39
|
+
const offs = [language.onKey(event => {
|
|
40
|
+
if (isShortcut(this.language.shortcuts.callHierarchy, event)) {
|
|
41
|
+
if (this.isOpen) {
|
|
42
|
+
this.setDirection(this.direction === 'incoming' ? 'outgoing' : 'incoming');
|
|
43
|
+
} else {
|
|
44
|
+
void this.open();
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return this.key(event);
|
|
49
|
+
}, KEY_PRIORITY.callHierarchy), editor.onTextChange(() => this.close())];
|
|
50
|
+
language.onDispose(() => {
|
|
51
|
+
for (const off of offs) {
|
|
52
|
+
off();
|
|
53
|
+
}
|
|
54
|
+
this.close();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
get isOpen() {
|
|
58
|
+
return this.language.popups.getState().callHierarchy !== null;
|
|
59
|
+
}
|
|
60
|
+
/* Whether a server of this document answers the three requests the tree is made of. */
|
|
61
|
+
get supported() {
|
|
62
|
+
const {
|
|
63
|
+
project,
|
|
64
|
+
uri
|
|
65
|
+
} = this.language;
|
|
66
|
+
const {
|
|
67
|
+
service
|
|
68
|
+
} = project;
|
|
69
|
+
return service.prepareCallHierarchy !== undefined && service.incomingCalls !== undefined && service.outgoingCalls !== undefined && service.supports(PREPARE, uri);
|
|
70
|
+
}
|
|
71
|
+
/* Opens the tree for the symbol at the position, on its callers unless told otherwise. */
|
|
72
|
+
async open(position = this.language.editor.getCaret(), direction = 'incoming') {
|
|
73
|
+
const {
|
|
74
|
+
editor,
|
|
75
|
+
project,
|
|
76
|
+
uri
|
|
77
|
+
} = this.language;
|
|
78
|
+
if (!this.supported) {
|
|
79
|
+
this.tell(this.say('unavailable'));
|
|
80
|
+
return;
|
|
112
81
|
}
|
|
113
|
-
close()
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
this.reset();
|
|
130
|
-
this.direction = direction;
|
|
131
|
-
this.seed();
|
|
132
|
-
const active = this.roots[0];
|
|
133
|
-
this.language.popups.setState({
|
|
134
|
-
callHierarchy: { ...view, direction, rows: rowsOf(this.nodes, this.roots), active, site: 0, sites: 0, preview: null }
|
|
135
|
-
});
|
|
136
|
-
this.select(active);
|
|
137
|
-
for (const root of this.roots) {
|
|
138
|
-
void this.load(root);
|
|
139
|
-
}
|
|
82
|
+
this.close();
|
|
83
|
+
const epoch = this.epoch;
|
|
84
|
+
let items;
|
|
85
|
+
try {
|
|
86
|
+
items = await project.service.prepareCallHierarchy(uri, position, {
|
|
87
|
+
signal: this.controller.signal
|
|
88
|
+
});
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (epoch === this.epoch && !(error instanceof StaleResultError)) {
|
|
91
|
+
this.tell(this.say('failed', {
|
|
92
|
+
message: messageOf(error)
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
140
96
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const node = this.nodes.get(id);
|
|
144
|
-
if (node === undefined) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
if (node.expanded) {
|
|
148
|
-
this.patch(id, { expanded: false });
|
|
149
|
-
const view = this.language.popups.getState().callHierarchy;
|
|
150
|
-
if (view !== null && this.hasAncestor(view.active, id)) {
|
|
151
|
-
this.select(id);
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
this.patch(id, { expanded: true });
|
|
156
|
-
if (node.load === 'idle' || node.load === 'failed') {
|
|
157
|
-
void this.load(id);
|
|
158
|
-
}
|
|
97
|
+
if (epoch !== this.epoch) {
|
|
98
|
+
return;
|
|
159
99
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
void this.load(id);
|
|
164
|
-
}
|
|
100
|
+
if (items === null || items.length === 0) {
|
|
101
|
+
this.tell(this.say('none'));
|
|
102
|
+
return;
|
|
165
103
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
104
|
+
this.language.peek.close();
|
|
105
|
+
this.prepared = items;
|
|
106
|
+
this.direction = direction;
|
|
107
|
+
this.seed();
|
|
108
|
+
const active = this.roots[0];
|
|
109
|
+
this.language.popups.setState({
|
|
110
|
+
callHierarchy: {
|
|
111
|
+
direction,
|
|
112
|
+
container: null,
|
|
113
|
+
name: items[0].name,
|
|
114
|
+
rows: rowsOf(this.nodes, this.roots),
|
|
115
|
+
active,
|
|
116
|
+
site: 0,
|
|
117
|
+
sites: 0,
|
|
118
|
+
preview: null
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
this.select(active);
|
|
122
|
+
// The editor draws a row once per id, so a tree opened over another needs an id of its own to get a container.
|
|
123
|
+
editor.setWidgets([{
|
|
124
|
+
id: `call-hierarchy-${epoch}`,
|
|
125
|
+
line: position.line,
|
|
126
|
+
height: CALL_HIERARCHY_HEIGHT,
|
|
127
|
+
render: container => this.mounted(container)
|
|
128
|
+
}], OWNER);
|
|
129
|
+
editor.focus();
|
|
130
|
+
for (const root of this.roots) {
|
|
131
|
+
void this.load(root);
|
|
179
132
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const sites = node?.sites.length ?? view.sites;
|
|
188
|
-
const next = node === undefined ? view.site : Math.max(0, Math.min(Math.max(0, sites - 1), site));
|
|
189
|
-
this.language.popups.setState({ callHierarchy: { ...view, active: id, site: next, sites, preview: node === undefined ? view.preview : null } });
|
|
190
|
-
if (node !== undefined) {
|
|
191
|
-
void this.preview(node, next);
|
|
192
|
-
}
|
|
133
|
+
}
|
|
134
|
+
close() {
|
|
135
|
+
this.reset();
|
|
136
|
+
if (this.language.popups.getState().callHierarchy === null) {
|
|
137
|
+
return;
|
|
193
138
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
139
|
+
this.language.popups.setState({
|
|
140
|
+
callHierarchy: null
|
|
141
|
+
});
|
|
142
|
+
this.language.editor.setWidgets([], OWNER);
|
|
143
|
+
this.language.editor.setInputPopup(null);
|
|
144
|
+
this.language.editor.focus();
|
|
145
|
+
}
|
|
146
|
+
/* Starts the tree over from the same symbols for the other direction. */
|
|
147
|
+
setDirection(direction) {
|
|
148
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
149
|
+
if (view === null || view.direction === direction) {
|
|
150
|
+
return;
|
|
200
151
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
152
|
+
this.reset();
|
|
153
|
+
this.direction = direction;
|
|
154
|
+
this.seed();
|
|
155
|
+
const active = this.roots[0];
|
|
156
|
+
this.language.popups.setState({
|
|
157
|
+
callHierarchy: {
|
|
158
|
+
...view,
|
|
159
|
+
direction,
|
|
160
|
+
rows: rowsOf(this.nodes, this.roots),
|
|
161
|
+
active,
|
|
162
|
+
site: 0,
|
|
163
|
+
sites: 0,
|
|
164
|
+
preview: null
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
this.select(active);
|
|
168
|
+
for (const root of this.roots) {
|
|
169
|
+
void this.load(root);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/* Opens a node, asking the server for its calls the first time, or folds it away. */
|
|
173
|
+
toggle(id) {
|
|
174
|
+
const node = this.nodes.get(id);
|
|
175
|
+
if (node === undefined) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (node.expanded) {
|
|
179
|
+
this.patch(id, {
|
|
180
|
+
expanded: false
|
|
181
|
+
});
|
|
182
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
183
|
+
if (view !== null && this.hasAncestor(view.active, id)) {
|
|
184
|
+
this.select(id);
|
|
185
|
+
}
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
this.patch(id, {
|
|
189
|
+
expanded: true
|
|
190
|
+
});
|
|
191
|
+
if (node.load === 'idle' || node.load === 'failed') {
|
|
192
|
+
void this.load(id);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/* Asks again for the calls of a node whose last try failed. */
|
|
196
|
+
retry(id) {
|
|
197
|
+
if (this.nodes.get(id)?.load === 'failed') {
|
|
198
|
+
void this.load(id);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/* Brings the next stretch of calls of a level. */
|
|
202
|
+
showMore(parent) {
|
|
203
|
+
const node = this.nodes.get(parent);
|
|
204
|
+
if (node === undefined) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
this.patch(parent, {
|
|
208
|
+
shown: Math.min(node.children.length, node.shown + CALL_LEVEL_LIMIT)
|
|
209
|
+
});
|
|
210
|
+
const first = node.children[node.shown];
|
|
211
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
212
|
+
// The row that offered more is gone once everything shows, so the selection moves on to what it brought.
|
|
213
|
+
if (first !== undefined && view?.active === moreIdOf(parent)) {
|
|
214
|
+
this.select(first);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/* Makes a row the active one and shows the code of its call. */
|
|
218
|
+
select(id, site = 0) {
|
|
219
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
220
|
+
const node = this.nodes.get(id);
|
|
221
|
+
if (view === null || !view.rows.some(row => row.id === id)) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const sites = node?.sites.length ?? view.sites;
|
|
225
|
+
const next = node === undefined ? view.site : Math.max(0, Math.min(Math.max(0, sites - 1), site));
|
|
226
|
+
this.language.popups.setState({
|
|
227
|
+
callHierarchy: {
|
|
228
|
+
...view,
|
|
229
|
+
active: id,
|
|
230
|
+
site: next,
|
|
231
|
+
sites,
|
|
232
|
+
preview: node === undefined ? view.preview : null
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
if (node !== undefined) {
|
|
236
|
+
void this.preview(node, next);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/* Steps through the places a call is made from when the active one has more than one. */
|
|
240
|
+
stepSite(direction) {
|
|
241
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
242
|
+
if (view !== null && view.sites > 1) {
|
|
243
|
+
this.select(view.active, (view.site + direction + view.sites) % view.sites);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/* Goes to the call of a row, or to the symbol of a root, and closes the tree. */
|
|
247
|
+
go(id) {
|
|
248
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
249
|
+
const node = this.nodes.get(id);
|
|
250
|
+
if (view === null || node === undefined) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const {
|
|
254
|
+
uri,
|
|
255
|
+
range
|
|
256
|
+
} = targetOf(node, id === view.active ? view.site : 0);
|
|
257
|
+
this.close();
|
|
258
|
+
this.language.goTo({
|
|
259
|
+
uri,
|
|
260
|
+
range
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
reset() {
|
|
264
|
+
this.epoch++;
|
|
265
|
+
this.previewEpoch++;
|
|
266
|
+
this.controller.abort();
|
|
267
|
+
this.controller = new AbortController();
|
|
268
|
+
this.nodes = new Map();
|
|
269
|
+
this.roots = [];
|
|
270
|
+
this.texts = new Map();
|
|
271
|
+
}
|
|
272
|
+
seed() {
|
|
273
|
+
const roots = rootsOf(this.prepared);
|
|
274
|
+
this.roots = roots.map(root => root.id);
|
|
275
|
+
this.nodes = new Map(roots.map(root => [root.id, root]));
|
|
276
|
+
}
|
|
277
|
+
mounted(container) {
|
|
278
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
279
|
+
if (view !== null && view.container !== container) {
|
|
280
|
+
this.language.popups.setState({
|
|
281
|
+
callHierarchy: {
|
|
282
|
+
...view,
|
|
283
|
+
container
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
revealRow(this.timers, container);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
patch(id, change) {
|
|
290
|
+
const node = this.nodes.get(id);
|
|
291
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
292
|
+
if (node === undefined || view === null) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
this.nodes.set(id, {
|
|
296
|
+
...node,
|
|
297
|
+
...change
|
|
298
|
+
});
|
|
299
|
+
this.language.popups.setState({
|
|
300
|
+
callHierarchy: {
|
|
301
|
+
...view,
|
|
302
|
+
rows: rowsOf(this.nodes, this.roots)
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
async load(id) {
|
|
307
|
+
const node = this.nodes.get(id);
|
|
308
|
+
if (node === undefined || node.load === 'loading') {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const {
|
|
312
|
+
service,
|
|
313
|
+
i18n
|
|
314
|
+
} = this.language.project;
|
|
315
|
+
const {
|
|
316
|
+
uri,
|
|
317
|
+
editor
|
|
318
|
+
} = this.language;
|
|
319
|
+
const {
|
|
320
|
+
direction,
|
|
321
|
+
epoch
|
|
322
|
+
} = this;
|
|
323
|
+
const options = {
|
|
324
|
+
signal: this.controller.signal,
|
|
325
|
+
parallel: true
|
|
326
|
+
};
|
|
327
|
+
this.patch(id, {
|
|
328
|
+
load: 'loading',
|
|
329
|
+
error: null
|
|
330
|
+
});
|
|
331
|
+
try {
|
|
332
|
+
const calls = direction === 'incoming' ? await service.incomingCalls(uri, node.item, options) : await service.outgoingCalls(uri, node.item, options);
|
|
333
|
+
if (epoch !== this.epoch) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const children = childrenOf(direction, node, calls ?? []);
|
|
337
|
+
for (const child of children) {
|
|
338
|
+
this.nodes.set(child.id, child);
|
|
339
|
+
}
|
|
340
|
+
this.patch(id, {
|
|
341
|
+
load: 'loaded',
|
|
342
|
+
children: children.map(child => child.id),
|
|
343
|
+
shown: Math.min(children.length, CALL_LEVEL_LIMIT)
|
|
344
|
+
});
|
|
345
|
+
editor.announce(i18n.t(`editor:language.callHierarchy.announce.${direction}`, {
|
|
346
|
+
count: children.length,
|
|
347
|
+
name: node.item.name
|
|
348
|
+
}));
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (epoch !== this.epoch) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (error instanceof StaleResultError) {
|
|
209
354
|
this.close();
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.controller = new AbortController();
|
|
217
|
-
this.nodes = new Map();
|
|
218
|
-
this.roots = [];
|
|
219
|
-
this.texts = new Map();
|
|
220
|
-
}
|
|
221
|
-
seed() {
|
|
222
|
-
const roots = rootsOf(this.prepared);
|
|
223
|
-
this.roots = roots.map((root) => root.id);
|
|
224
|
-
this.nodes = new Map(roots.map((root) => [root.id, root]));
|
|
225
|
-
}
|
|
226
|
-
mounted(container) {
|
|
227
|
-
const view = this.language.popups.getState().callHierarchy;
|
|
228
|
-
if (view !== null && view.container !== container) {
|
|
229
|
-
this.language.popups.setState({ callHierarchy: { ...view, container } });
|
|
230
|
-
revealRow(this.timers, container);
|
|
231
|
-
}
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
this.patch(id, {
|
|
358
|
+
load: 'failed',
|
|
359
|
+
error: messageOf(error)
|
|
360
|
+
});
|
|
232
361
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
362
|
+
}
|
|
363
|
+
async preview(node, site) {
|
|
364
|
+
const {
|
|
365
|
+
project
|
|
366
|
+
} = this.language;
|
|
367
|
+
const epoch = ++this.previewEpoch;
|
|
368
|
+
const {
|
|
369
|
+
uri,
|
|
370
|
+
range
|
|
371
|
+
} = targetOf(node, site);
|
|
372
|
+
let text = this.texts.get(uri);
|
|
373
|
+
if (text === undefined) {
|
|
374
|
+
try {
|
|
375
|
+
text = (await project.readText(uri)) ?? undefined;
|
|
376
|
+
} catch {
|
|
377
|
+
// A file that cannot be read shows no code, as one that is no text file does.
|
|
378
|
+
text = undefined;
|
|
379
|
+
}
|
|
380
|
+
if (epoch !== this.previewEpoch) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (text !== undefined) {
|
|
384
|
+
this.texts.set(uri, text);
|
|
385
|
+
}
|
|
241
386
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const { service, i18n } = this.language.project;
|
|
248
|
-
const { uri, editor } = this.language;
|
|
249
|
-
const { direction, epoch } = this;
|
|
250
|
-
const options = { signal: this.controller.signal, parallel: true };
|
|
251
|
-
this.patch(id, { load: 'loading', error: null });
|
|
252
|
-
try {
|
|
253
|
-
const calls = direction === 'incoming' ? await service.incomingCalls(uri, node.item, options) : await service.outgoingCalls(uri, node.item, options);
|
|
254
|
-
if (epoch !== this.epoch) {
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
const children = childrenOf(direction, node, calls ?? []);
|
|
258
|
-
for (const child of children) {
|
|
259
|
-
this.nodes.set(child.id, child);
|
|
260
|
-
}
|
|
261
|
-
this.patch(id, { load: 'loaded', children: children.map((child) => child.id), shown: Math.min(children.length, CALL_LEVEL_LIMIT) });
|
|
262
|
-
editor.announce(i18n.t(`editor:language.callHierarchy.announce.${direction}`, { count: children.length, name: node.item.name }));
|
|
263
|
-
}
|
|
264
|
-
catch (error) {
|
|
265
|
-
if (epoch !== this.epoch) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
if (error instanceof StaleResultError) {
|
|
269
|
-
this.close();
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
this.patch(id, { load: 'failed', error: messageOf(error) });
|
|
273
|
-
}
|
|
387
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
388
|
+
if (view === null || view.active !== node.id) {
|
|
389
|
+
return;
|
|
274
390
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
391
|
+
const snippet = text === undefined ? null : snippetOf(text, range.start.line, range);
|
|
392
|
+
this.language.popups.setState({
|
|
393
|
+
callHierarchy: {
|
|
394
|
+
...view,
|
|
395
|
+
preview: snippet === null ? null : {
|
|
396
|
+
...snippet,
|
|
397
|
+
uri
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
/* Whether a row stands under a node; the `more` and `status` rows belong to the node they are about. */
|
|
403
|
+
hasAncestor(id, ancestor) {
|
|
404
|
+
const owner = [moreIdOf(''), statusIdOf('')].map(suffix => id.endsWith(suffix) ? id.slice(0, -suffix.length) : null).find(found => found !== null);
|
|
405
|
+
if (owner !== undefined && owner !== null) {
|
|
406
|
+
return owner === ancestor || this.hasAncestor(owner, ancestor);
|
|
407
|
+
}
|
|
408
|
+
for (let node = this.nodes.get(id); node !== undefined && node.parent !== null; node = this.nodes.get(node.parent)) {
|
|
409
|
+
if (node.parent === ancestor) {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
key(event) {
|
|
416
|
+
const view = this.language.popups.getState().callHierarchy;
|
|
417
|
+
if (view === null || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey || event.isComposing) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
const steps = stepsOf(view.rows);
|
|
421
|
+
const index = steps.findIndex(row => row.id === view.active);
|
|
422
|
+
const row = steps[index];
|
|
423
|
+
switch (event.key) {
|
|
424
|
+
case 'ArrowDown':
|
|
425
|
+
this.land(steps[Math.min(steps.length - 1, index + 1)]);
|
|
426
|
+
return true;
|
|
427
|
+
case 'ArrowUp':
|
|
428
|
+
this.land(steps[Math.max(0, index - 1)]);
|
|
429
|
+
return true;
|
|
430
|
+
case 'Home':
|
|
431
|
+
this.land(steps[0]);
|
|
432
|
+
return true;
|
|
433
|
+
case 'End':
|
|
434
|
+
this.land(steps.at(-1));
|
|
435
|
+
return true;
|
|
436
|
+
case 'ArrowRight':
|
|
437
|
+
this.expandOrEnter(row, steps[index + 1]);
|
|
438
|
+
return true;
|
|
439
|
+
case 'ArrowLeft':
|
|
440
|
+
this.collapseOrLeave(row);
|
|
441
|
+
return true;
|
|
442
|
+
case 'Enter':
|
|
443
|
+
if (row?.kind === 'more') {
|
|
444
|
+
this.showMore(row.parent);
|
|
445
|
+
} else if (row !== undefined) {
|
|
446
|
+
this.go(row.id);
|
|
447
|
+
}
|
|
448
|
+
return true;
|
|
449
|
+
case 'Escape':
|
|
450
|
+
this.close();
|
|
451
|
+
return true;
|
|
452
|
+
default:
|
|
315
453
|
return false;
|
|
316
454
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
const steps = stepsOf(view.rows);
|
|
323
|
-
const index = steps.findIndex((row) => row.id === view.active);
|
|
324
|
-
const row = steps[index];
|
|
325
|
-
switch (event.key) {
|
|
326
|
-
case 'ArrowDown':
|
|
327
|
-
this.land(steps[Math.min(steps.length - 1, index + 1)]);
|
|
328
|
-
return true;
|
|
329
|
-
case 'ArrowUp':
|
|
330
|
-
this.land(steps[Math.max(0, index - 1)]);
|
|
331
|
-
return true;
|
|
332
|
-
case 'Home':
|
|
333
|
-
this.land(steps[0]);
|
|
334
|
-
return true;
|
|
335
|
-
case 'End':
|
|
336
|
-
this.land(steps.at(-1));
|
|
337
|
-
return true;
|
|
338
|
-
case 'ArrowRight':
|
|
339
|
-
this.expandOrEnter(row, steps[index + 1]);
|
|
340
|
-
return true;
|
|
341
|
-
case 'ArrowLeft':
|
|
342
|
-
this.collapseOrLeave(row);
|
|
343
|
-
return true;
|
|
344
|
-
case 'Enter':
|
|
345
|
-
if (row?.kind === 'more') {
|
|
346
|
-
this.showMore(row.parent);
|
|
347
|
-
}
|
|
348
|
-
else if (row !== undefined) {
|
|
349
|
-
this.go(row.id);
|
|
350
|
-
}
|
|
351
|
-
return true;
|
|
352
|
-
case 'Escape':
|
|
353
|
-
this.close();
|
|
354
|
-
return true;
|
|
355
|
-
default:
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
455
|
+
}
|
|
456
|
+
land(row) {
|
|
457
|
+
if (row !== undefined) {
|
|
458
|
+
this.select(row.id);
|
|
358
459
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
460
|
+
}
|
|
461
|
+
/* Right opens a closed node, tries a failed one again, and steps into an open one. */
|
|
462
|
+
expandOrEnter(row, next) {
|
|
463
|
+
if (row?.kind !== 'node') {
|
|
464
|
+
return;
|
|
363
465
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
this.toggle(row.id);
|
|
371
|
-
}
|
|
372
|
-
else if (row.load === 'failed') {
|
|
373
|
-
this.retry(row.id);
|
|
374
|
-
}
|
|
375
|
-
else if (next !== undefined && next.level > row.level) {
|
|
376
|
-
this.land(next);
|
|
377
|
-
}
|
|
466
|
+
if (!row.expanded) {
|
|
467
|
+
this.toggle(row.id);
|
|
468
|
+
} else if (row.load === 'failed') {
|
|
469
|
+
this.retry(row.id);
|
|
470
|
+
} else if (next !== undefined && next.level > row.level) {
|
|
471
|
+
this.land(next);
|
|
378
472
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
if (row.kind === 'node' && row.expanded && !row.leaf) {
|
|
385
|
-
this.toggle(row.id);
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
const parent = row.kind === 'node' ? (this.nodes.get(row.id)?.parent ?? null) : row.parent;
|
|
389
|
-
if (parent !== null) {
|
|
390
|
-
this.select(parent);
|
|
391
|
-
}
|
|
473
|
+
}
|
|
474
|
+
/* Left closes an open node and steps out of a closed one. */
|
|
475
|
+
collapseOrLeave(row) {
|
|
476
|
+
if (row === undefined) {
|
|
477
|
+
return;
|
|
392
478
|
}
|
|
393
|
-
|
|
394
|
-
|
|
479
|
+
if (row.kind === 'node' && row.expanded && !row.leaf) {
|
|
480
|
+
this.toggle(row.id);
|
|
481
|
+
return;
|
|
395
482
|
}
|
|
396
|
-
|
|
397
|
-
|
|
483
|
+
const parent = row.kind === 'node' ? this.nodes.get(row.id)?.parent ?? null : row.parent;
|
|
484
|
+
if (parent !== null) {
|
|
485
|
+
this.select(parent);
|
|
398
486
|
}
|
|
399
|
-
}
|
|
487
|
+
}
|
|
488
|
+
tell(title) {
|
|
489
|
+
this.language.project.host.notify?.({
|
|
490
|
+
id: TOAST_ID,
|
|
491
|
+
kind: 'error',
|
|
492
|
+
title
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
say(key, options) {
|
|
496
|
+
return this.language.project.i18n.t(`editor:language.callHierarchy.${key}`, options);
|
|
497
|
+
}
|
|
498
|
+
}
|