@adecore/editor-react 0.31.12 → 0.33.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/project-language.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { disposeSnippetTransforms } from './snippet-transform-queue.js';
|
|
2
|
-
import i18next
|
|
2
|
+
import i18next from 'i18next';
|
|
3
3
|
import { fileUriToPath, pathToFileUri } from '@adecore/lsp';
|
|
4
4
|
import { NavigationHistory } from './navigation-history.js';
|
|
5
5
|
import { ProjectProblems, serviceProblems } from './project-problems.js';
|
|
@@ -8,236 +8,253 @@ import { relativeTo } from './paths.js';
|
|
|
8
8
|
import { PANEL_BODY_HEIGHT } from './panel-size.js';
|
|
9
9
|
/* Sends one editor's edits to the document, holding them until the document is open. */
|
|
10
10
|
class DocumentSync {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
11
|
+
ready;
|
|
12
|
+
editor;
|
|
13
|
+
service;
|
|
14
|
+
uri;
|
|
15
|
+
stop;
|
|
16
|
+
pending = [];
|
|
17
|
+
opened = false;
|
|
18
|
+
disposed = false;
|
|
19
|
+
constructor(service, uri, languageId, editor) {
|
|
20
|
+
this.service = service;
|
|
21
|
+
this.uri = uri;
|
|
22
|
+
this.editor = editor;
|
|
23
|
+
this.stop = editor.onTextChange(change => this.changed(change.changes));
|
|
24
|
+
this.ready = service.openDocument({
|
|
25
|
+
uri,
|
|
26
|
+
languageId,
|
|
27
|
+
text: editor.getText()
|
|
28
|
+
}).then(() => {
|
|
29
|
+
this.opened = true;
|
|
30
|
+
if (!this.disposed) {
|
|
31
|
+
this.flush();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
// A failed open is also a document nothing can be asked of; the features' own requests say so.
|
|
35
|
+
this.ready.catch(() => undefined);
|
|
36
|
+
}
|
|
37
|
+
get text() {
|
|
38
|
+
return this.editor.getText();
|
|
39
|
+
}
|
|
40
|
+
dispose() {
|
|
41
|
+
this.disposed = true;
|
|
42
|
+
this.pending = [];
|
|
43
|
+
this.stop();
|
|
44
|
+
}
|
|
45
|
+
changed(changes) {
|
|
46
|
+
this.pending.push(...changes);
|
|
47
|
+
if (this.opened) {
|
|
48
|
+
this.flush();
|
|
46
49
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const changes = this.pending;
|
|
52
|
-
this.pending = [];
|
|
53
|
-
void this.service.changeDocument(this.uri, changes).catch(() => undefined);
|
|
50
|
+
}
|
|
51
|
+
flush() {
|
|
52
|
+
if (this.pending.length === 0) {
|
|
53
|
+
return;
|
|
54
54
|
}
|
|
55
|
+
const changes = this.pending;
|
|
56
|
+
this.pending = [];
|
|
57
|
+
void this.service.changeDocument(this.uri, changes).catch(() => undefined);
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
60
|
function filesOf(targets) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
return targets.map(target => {
|
|
62
|
+
const {
|
|
63
|
+
path,
|
|
64
|
+
directory
|
|
65
|
+
} = typeof target === 'string' ? {
|
|
66
|
+
path: target,
|
|
67
|
+
directory: false
|
|
68
|
+
} : {
|
|
69
|
+
path: target.path,
|
|
70
|
+
directory: target.directory === true
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
uri: pathToFileUri(path),
|
|
74
|
+
directory
|
|
75
|
+
};
|
|
76
|
+
});
|
|
61
77
|
}
|
|
62
78
|
/*
|
|
63
79
|
* A shared language service and document ownership for the editors of a project. Two editors on the same
|
|
64
80
|
* file hold one document, and only the first one sends changes, since both would report the same edit.
|
|
65
81
|
*/
|
|
66
82
|
export class ProjectLanguage {
|
|
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
|
-
this.panelBodyHeight = height;
|
|
100
|
-
this.panelListeners.forEach((listener) => listener(height));
|
|
101
|
-
this.host.onPanelResize?.(height);
|
|
102
|
-
}
|
|
103
|
-
pathOfLocation(uri) {
|
|
104
|
-
if (this.host.pathOfUri !== undefined) {
|
|
105
|
-
return this.host.pathOfUri(uri);
|
|
106
|
-
}
|
|
107
|
-
const path = fileUriToPath(uri);
|
|
108
|
-
return path !== null && this.folder !== '' ? relativeTo(path, this.folder) : path;
|
|
109
|
-
}
|
|
110
|
-
/* Makes an edit of a language server: an open document takes it as one undo step and any other file gets an unsaved draft. */
|
|
111
|
-
applyWorkspaceEdit(edit) {
|
|
112
|
-
const { service } = this;
|
|
113
|
-
return applyWorkspaceEdit(edit, {
|
|
114
|
-
editorOf: (uri) => this.holders.get(uri)?.editors[0],
|
|
115
|
-
files: this.files,
|
|
116
|
-
...(service.versionOf === undefined ? {} : { versionOf: (uri) => service.versionOf(uri) })
|
|
117
|
-
});
|
|
83
|
+
service;
|
|
84
|
+
host;
|
|
85
|
+
i18n;
|
|
86
|
+
folder;
|
|
87
|
+
problems;
|
|
88
|
+
history = new NavigationHistory();
|
|
89
|
+
holders = new Map();
|
|
90
|
+
files;
|
|
91
|
+
/* The body height of the peek and call hierarchy panels, shared by the editors of the project. */
|
|
92
|
+
panelBodyHeight;
|
|
93
|
+
panelListeners = new Set();
|
|
94
|
+
pendingCaret = null;
|
|
95
|
+
lastPlace = null;
|
|
96
|
+
disposed = false;
|
|
97
|
+
constructor(service, host = {}) {
|
|
98
|
+
this.service = service;
|
|
99
|
+
this.host = host;
|
|
100
|
+
this.i18n = host.i18n ?? i18next;
|
|
101
|
+
this.folder = host.folder ?? '';
|
|
102
|
+
this.files = host.files ?? null;
|
|
103
|
+
this.panelBodyHeight = host.panelBodyHeight ?? PANEL_BODY_HEIGHT;
|
|
104
|
+
this.problems = new ProjectProblems(host.problemSource ?? serviceProblems(service, uri => this.pathOfLocation(uri) ?? uri));
|
|
105
|
+
}
|
|
106
|
+
/* Open panels of other editors of the project follow a resize. */
|
|
107
|
+
onPanelBodyChange(listener) {
|
|
108
|
+
this.panelListeners.add(listener);
|
|
109
|
+
return () => this.panelListeners.delete(listener);
|
|
110
|
+
}
|
|
111
|
+
resizePanelBody(height) {
|
|
112
|
+
if (height === this.panelBodyHeight) {
|
|
113
|
+
return;
|
|
118
114
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
this.panelBodyHeight = height;
|
|
116
|
+
this.panelListeners.forEach(listener => listener(height));
|
|
117
|
+
this.host.onPanelResize?.(height);
|
|
118
|
+
}
|
|
119
|
+
pathOfLocation(uri) {
|
|
120
|
+
if (this.host.pathOfUri !== undefined) {
|
|
121
|
+
return this.host.pathOfUri(uri);
|
|
125
122
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
123
|
+
const path = fileUriToPath(uri);
|
|
124
|
+
return path !== null && this.folder !== '' ? relativeTo(path, this.folder) : path;
|
|
125
|
+
}
|
|
126
|
+
/* Makes an edit of a language server: an open document takes it as one undo step and any other file gets an unsaved draft. */
|
|
127
|
+
applyWorkspaceEdit(edit) {
|
|
128
|
+
const {
|
|
129
|
+
service
|
|
130
|
+
} = this;
|
|
131
|
+
return applyWorkspaceEdit(edit, {
|
|
132
|
+
editorOf: uri => this.holders.get(uri)?.editors[0],
|
|
133
|
+
files: this.files,
|
|
134
|
+
...(service.versionOf === undefined ? {} : {
|
|
135
|
+
versionOf: uri => service.versionOf(uri)
|
|
136
|
+
})
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/*
|
|
140
|
+
* What the servers want changed before files are made, for a host that makes them outside a language server's
|
|
141
|
+
* edit: apply the edit with `applyWorkspaceEdit`, then make the files. Null when no server has anything to say.
|
|
142
|
+
*/
|
|
143
|
+
willCreateFiles(targets) {
|
|
144
|
+
return this.service.willCreateFiles?.(filesOf(targets)) ?? Promise.resolve(null);
|
|
145
|
+
}
|
|
146
|
+
/* Tells the servers that files were made, once they are. */
|
|
147
|
+
didCreateFiles(targets) {
|
|
148
|
+
return this.service.didCreateFiles?.(filesOf(targets)) ?? Promise.resolve();
|
|
149
|
+
}
|
|
150
|
+
/* What the servers want changed before files are deleted, such as the references to them; null when no server has anything to say. */
|
|
151
|
+
willDeleteFiles(targets) {
|
|
152
|
+
return this.service.willDeleteFiles?.(filesOf(targets)) ?? Promise.resolve(null);
|
|
153
|
+
}
|
|
154
|
+
/* Tells the servers that files were deleted, once they are. */
|
|
155
|
+
didDeleteFiles(targets) {
|
|
156
|
+
return this.service.didDeleteFiles?.(filesOf(targets)) ?? Promise.resolve();
|
|
157
|
+
}
|
|
158
|
+
/* The text of a file as it stands now: an open document's, else a draft's or the machine's; null when it is no text file. */
|
|
159
|
+
async readText(uri) {
|
|
160
|
+
const open = this.holders.get(uri)?.sync.text;
|
|
161
|
+
if (open !== undefined) {
|
|
162
|
+
return open;
|
|
137
163
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
164
|
+
const path = fileUriToPath(uri);
|
|
165
|
+
return path === null || this.files === null ? null : (await this.files.read(path))?.text ?? null;
|
|
166
|
+
}
|
|
167
|
+
/*
|
|
168
|
+
* Opens the file of a place on its line. A file opens on a line only, so the column is kept here until the editor
|
|
169
|
+
* that shows the line asks for it with `takeCaret`.
|
|
170
|
+
*/
|
|
171
|
+
openPlace(place) {
|
|
172
|
+
this.pendingCaret = place;
|
|
173
|
+
this.host.openPlace?.(place);
|
|
174
|
+
}
|
|
175
|
+
/* Where an editor's caret stands now, so a jump from a surface without an editor, such as the Problems panel, still knows what it left. */
|
|
176
|
+
noteCaret(place) {
|
|
177
|
+
this.lastPlace = place;
|
|
178
|
+
}
|
|
179
|
+
/* Opens a place from outside any editor and remembers the caret that was last seen. */
|
|
180
|
+
jumpTo(place) {
|
|
181
|
+
if (this.lastPlace !== null) {
|
|
182
|
+
this.history.record(this.lastPlace);
|
|
146
183
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
184
|
+
this.openPlace(place);
|
|
185
|
+
}
|
|
186
|
+
/* The column an opened place waits for, once the editor of its file has put its caret on the line; each place is asked for once. */
|
|
187
|
+
takeCaret(uri, line) {
|
|
188
|
+
const pending = this.pendingCaret;
|
|
189
|
+
if (pending === null || pending.uri !== uri || pending.position.line !== line) {
|
|
190
|
+
return null;
|
|
154
191
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
192
|
+
this.pendingCaret = null;
|
|
193
|
+
return pending.position;
|
|
194
|
+
}
|
|
195
|
+
/* Opens `uri` for the editor, or joins the editors that already hold it. */
|
|
196
|
+
acquire(uri, languageId, editor) {
|
|
197
|
+
if (this.disposed) {
|
|
198
|
+
throw new Error('The project language is disposed');
|
|
158
199
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
200
|
+
let holder = this.holders.get(uri);
|
|
201
|
+
if (holder === undefined) {
|
|
202
|
+
holder = {
|
|
203
|
+
editors: [],
|
|
204
|
+
sync: new DocumentSync(this.service, uri, languageId, editor),
|
|
205
|
+
languageId
|
|
206
|
+
};
|
|
207
|
+
this.holders.set(uri, holder);
|
|
165
208
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
209
|
+
holder.editors.push(editor);
|
|
210
|
+
let released = false;
|
|
211
|
+
return {
|
|
212
|
+
uri,
|
|
213
|
+
service: this.service,
|
|
214
|
+
get ready() {
|
|
215
|
+
return holder.sync.ready;
|
|
216
|
+
},
|
|
217
|
+
release: () => {
|
|
218
|
+
if (!released) {
|
|
219
|
+
released = true;
|
|
220
|
+
this.release(uri, editor);
|
|
171
221
|
}
|
|
172
|
-
|
|
173
|
-
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
release(uri, editor) {
|
|
226
|
+
const holder = this.holders.get(uri);
|
|
227
|
+
if (holder === undefined) {
|
|
228
|
+
return;
|
|
174
229
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
this.holders.set(uri, holder);
|
|
230
|
+
holder.editors.splice(holder.editors.indexOf(editor), 1);
|
|
231
|
+
const next = holder.editors[0];
|
|
232
|
+
if (next === undefined) {
|
|
233
|
+
holder.sync.dispose();
|
|
234
|
+
this.holders.delete(uri);
|
|
235
|
+
void holder.sync.ready.catch(() => undefined).then(() => {
|
|
236
|
+
if (this.holders.has(uri)) {
|
|
237
|
+
return undefined;
|
|
184
238
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return holder.sync.ready;
|
|
192
|
-
},
|
|
193
|
-
release: () => {
|
|
194
|
-
if (!released) {
|
|
195
|
-
released = true;
|
|
196
|
-
this.release(uri, editor);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
};
|
|
239
|
+
return this.service.closeDocument(uri);
|
|
240
|
+
}).catch(() => undefined);
|
|
241
|
+
} else if (holder.sync.editor === editor) {
|
|
242
|
+
// The editor that sent the changes is gone; the next one takes over and opens the document with its own text.
|
|
243
|
+
holder.sync.dispose();
|
|
244
|
+
holder.sync = new DocumentSync(this.service, uri, holder.languageId, next);
|
|
200
245
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
holder.editors.splice(holder.editors.indexOf(editor), 1);
|
|
207
|
-
const next = holder.editors[0];
|
|
208
|
-
if (next === undefined) {
|
|
209
|
-
holder.sync.dispose();
|
|
210
|
-
this.holders.delete(uri);
|
|
211
|
-
void holder.sync.ready
|
|
212
|
-
.catch(() => undefined)
|
|
213
|
-
.then(() => {
|
|
214
|
-
if (this.holders.has(uri)) {
|
|
215
|
-
return undefined;
|
|
216
|
-
}
|
|
217
|
-
return this.service.closeDocument(uri);
|
|
218
|
-
})
|
|
219
|
-
.catch(() => undefined);
|
|
220
|
-
}
|
|
221
|
-
else if (holder.sync.editor === editor) {
|
|
222
|
-
// The editor that sent the changes is gone; the next one takes over and opens the document with its own text.
|
|
223
|
-
holder.sync.dispose();
|
|
224
|
-
holder.sync = new DocumentSync(this.service, uri, holder.languageId, next);
|
|
225
|
-
}
|
|
246
|
+
}
|
|
247
|
+
dispose() {
|
|
248
|
+
if (this.disposed) {
|
|
249
|
+
return;
|
|
226
250
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
disposeSnippetTransforms(this);
|
|
233
|
-
for (const [uri, holder] of this.holders) {
|
|
234
|
-
holder.sync.dispose();
|
|
235
|
-
void holder.sync.ready
|
|
236
|
-
.catch(() => undefined)
|
|
237
|
-
.then(() => this.service.closeDocument(uri))
|
|
238
|
-
.catch(() => undefined);
|
|
239
|
-
}
|
|
240
|
-
this.holders.clear();
|
|
241
|
-
this.problems.dispose();
|
|
251
|
+
this.disposed = true;
|
|
252
|
+
disposeSnippetTransforms(this);
|
|
253
|
+
for (const [uri, holder] of this.holders) {
|
|
254
|
+
holder.sync.dispose();
|
|
255
|
+
void holder.sync.ready.catch(() => undefined).then(() => this.service.closeDocument(uri)).catch(() => undefined);
|
|
242
256
|
}
|
|
243
|
-
|
|
257
|
+
this.holders.clear();
|
|
258
|
+
this.problems.dispose();
|
|
259
|
+
}
|
|
260
|
+
}
|
package/dist/project-problems.js
CHANGED
|
@@ -1,85 +1,97 @@
|
|
|
1
1
|
import { comparePositions, problemCountsOf, severityOf } from './diagnostics-model.js';
|
|
2
|
-
const SEVERITY_ORDER = {
|
|
2
|
+
const SEVERITY_ORDER = {
|
|
3
|
+
error: 0,
|
|
4
|
+
warning: 1,
|
|
5
|
+
info: 2,
|
|
6
|
+
hint: 3
|
|
7
|
+
};
|
|
3
8
|
/* Worst first, then in the order of the file. */
|
|
4
9
|
export function compareRows(left, right) {
|
|
5
|
-
|
|
6
|
-
comparePositions(left.diagnostic.range.start, right.diagnostic.range.start));
|
|
10
|
+
return SEVERITY_ORDER[severityOf(left.diagnostic)] - SEVERITY_ORDER[severityOf(right.diagnostic)] || comparePositions(left.diagnostic.range.start, right.diagnostic.range.start);
|
|
7
11
|
}
|
|
8
12
|
/* The diagnostics a service reports, by the stored path `pathOf` gives each URI. */
|
|
9
|
-
export function serviceProblems(service, pathOf =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
export function serviceProblems(service, pathOf = uri => uri) {
|
|
14
|
+
return listener => {
|
|
15
|
+
const subscription = service.onDiagnostics(report => listener({
|
|
16
|
+
path: pathOf(report.uri),
|
|
17
|
+
server: report.source,
|
|
18
|
+
diagnostics: report.diagnostics
|
|
19
|
+
}));
|
|
20
|
+
return () => subscription.dispose();
|
|
21
|
+
};
|
|
14
22
|
}
|
|
15
23
|
/*
|
|
16
24
|
* Each report replaces the previous diagnostics from that source for the file. Files with no
|
|
17
25
|
* remaining problems drop out. Hints remain editor annotations rather than listed problems.
|
|
18
26
|
*/
|
|
19
27
|
export class ProjectProblems {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
reports = new Map();
|
|
29
|
+
files = new Map();
|
|
30
|
+
listeners = new Set();
|
|
31
|
+
stop;
|
|
32
|
+
/* The paths of `files` in order; null once a file came or went. */
|
|
33
|
+
order = [];
|
|
34
|
+
/* Made on first read after a report, so a project nobody lists does no sorting. */
|
|
35
|
+
snapshot = [];
|
|
36
|
+
/* A service stands for `serviceProblems(service, pathOf)`. */
|
|
37
|
+
constructor(source, pathOf) {
|
|
38
|
+
const listen = typeof source === 'function' ? source : serviceProblems(source, pathOf);
|
|
39
|
+
this.stop = listen(report => this.report(report.path, report.server, report.diagnostics));
|
|
40
|
+
}
|
|
41
|
+
report(path, server, diagnostics) {
|
|
42
|
+
const kept = diagnostics.filter(diagnostic => severityOf(diagnostic) !== 'hint');
|
|
43
|
+
const servers = this.reports.get(path) ?? new Map();
|
|
44
|
+
if (kept.length === 0 && !servers.has(server)) {
|
|
45
|
+
// A clean file reported clean again, as servers do after every edit.
|
|
46
|
+
return;
|
|
32
47
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// A clean file reported clean again, as servers do after every edit.
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (kept.length === 0) {
|
|
41
|
-
servers.delete(server);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
servers.set(server, kept);
|
|
45
|
-
}
|
|
46
|
-
if (servers.size === 0) {
|
|
47
|
-
this.reports.delete(path);
|
|
48
|
-
this.files.delete(path);
|
|
49
|
-
this.order = null;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
if (!this.files.has(path)) {
|
|
53
|
-
this.order = null;
|
|
54
|
-
}
|
|
55
|
-
this.reports.set(path, servers);
|
|
56
|
-
const rows = [...servers].flatMap(([name, list]) => list.map((diagnostic) => ({ diagnostic, server: name }))).sort(compareRows);
|
|
57
|
-
this.files.set(path, { path, rows });
|
|
58
|
-
}
|
|
59
|
-
this.snapshot = null;
|
|
60
|
-
for (const listener of [...this.listeners]) {
|
|
61
|
-
listener();
|
|
62
|
-
}
|
|
48
|
+
if (kept.length === 0) {
|
|
49
|
+
servers.delete(server);
|
|
50
|
+
} else {
|
|
51
|
+
servers.set(server, kept);
|
|
63
52
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
53
|
+
if (servers.size === 0) {
|
|
54
|
+
this.reports.delete(path);
|
|
55
|
+
this.files.delete(path);
|
|
56
|
+
this.order = null;
|
|
57
|
+
} else {
|
|
58
|
+
if (!this.files.has(path)) {
|
|
59
|
+
this.order = null;
|
|
60
|
+
}
|
|
61
|
+
this.reports.set(path, servers);
|
|
62
|
+
const rows = [...servers].flatMap(([name, list]) => list.map(diagnostic => ({
|
|
63
|
+
diagnostic,
|
|
64
|
+
server: name
|
|
65
|
+
}))).sort(compareRows);
|
|
66
|
+
this.files.set(path, {
|
|
67
|
+
path,
|
|
68
|
+
rows
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
this.snapshot = null;
|
|
72
|
+
for (const listener of [...this.listeners]) {
|
|
73
|
+
listener();
|
|
81
74
|
}
|
|
75
|
+
}
|
|
76
|
+
/* The same array until the next report, which is what a store a component reads must hand out. */
|
|
77
|
+
getSnapshot = () => {
|
|
78
|
+
if (this.snapshot === null) {
|
|
79
|
+
this.order ??= [...this.files.keys()].sort((left, right) => left.localeCompare(right));
|
|
80
|
+
this.snapshot = this.order.map(path => this.files.get(path));
|
|
81
|
+
}
|
|
82
|
+
return this.snapshot;
|
|
83
|
+
};
|
|
84
|
+
subscribe = listener => {
|
|
85
|
+
this.listeners.add(listener);
|
|
86
|
+
return () => {
|
|
87
|
+
this.listeners.delete(listener);
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
dispose() {
|
|
91
|
+
this.stop();
|
|
92
|
+
this.listeners.clear();
|
|
93
|
+
}
|
|
82
94
|
}
|
|
83
95
|
export function countsOf(files) {
|
|
84
|
-
|
|
85
|
-
}
|
|
96
|
+
return problemCountsOf(files.flatMap(file => file.rows.map(row => row.diagnostic)));
|
|
97
|
+
}
|