@codingame/monaco-vscode-api 1.83.15-next.0 → 1.83.16
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/README.md +430 -0
- package/contributions.js +3 -0
- package/localExtensionHost.js +3 -2
- package/missing-services.js +57 -1
- package/monaco-editor-treemending.patch +3375 -3375
- package/package.json +6 -6
- package/vscode/src/vs/base/common/prefixTree.js +130 -0
- package/vscode/src/vs/platform/actions/browser/floatingMenu.js +26 -2
- package/vscode/src/vs/platform/terminal/common/capabilities/bufferMarkCapability.js +41 -0
- package/vscode/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.js +566 -0
- package/vscode/src/vs/platform/terminal/common/capabilities/cwdDetectionCapability.js +29 -0
- package/vscode/src/vs/platform/terminal/common/capabilities/partialCommandDetectionCapability.js +48 -0
- package/vscode/src/vs/platform/terminal/common/capabilities/terminalCapabilityStore.js +94 -0
- package/vscode/src/vs/platform/terminal/common/terminalEnvironment.js +37 -0
- package/vscode/src/vs/platform/terminal/common/terminalStrings.js +16 -0
- package/vscode/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.js +319 -0
- package/vscode/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.js +91 -1
- package/vscode/src/vs/workbench/contrib/format/browser/formatActionsMultiple.js +423 -0
- package/vscode/src/vs/workbench/contrib/format/browser/formatActionsNone.js +82 -0
- package/vscode/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.js +564 -11
- package/vscode/src/vs/workbench/contrib/scm/common/scm.js +9 -1
- package/vscode/src/vs/workbench/contrib/terminal/browser/detachedTerminal.js +67 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/terminalExtensions.js +25 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/terminalIcons.js +64 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/widgets/widgetManager.js +36 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.js +538 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/xterm/decorationStyles.js +104 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/xterm/markNavigationAddon.js +416 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/xterm/suggestAddon.js +390 -0
- package/vscode/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.js +799 -0
- package/vscode/src/vs/workbench/contrib/testing/common/getComputedState.js +101 -0
- package/vscode/src/vs/workbench/contrib/testing/common/observableValue.js +30 -0
- package/vscode/src/vs/workbench/contrib/testing/common/storedValue.js +36 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testExplorerFilterState.js +116 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testProfileService.js +172 -1
- package/vscode/src/vs/workbench/contrib/testing/common/testResult.js +384 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testResultService.js +156 -1
- package/vscode/src/vs/workbench/contrib/testing/common/testResultStorage.js +156 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testService.js +75 -1
- package/vscode/src/vs/workbench/contrib/testing/common/testTypes.js +9 -1
- package/vscode/src/vs/workbench/contrib/testing/common/testingContextKeys.js +179 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testingContinuousRunService.js +102 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testingDecorations.js +29 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testingPeekOpener.js +3 -0
- package/vscode/src/vs/workbench/contrib/testing/common/testingStates.js +47 -0
- package/vscode/src/vs/workbench/services/authentication/browser/authenticationService.js +594 -2
- package/vscode/src/vs/workbench/services/extensions/browser/extensionUrlHandler.js +307 -1
- package/vscode/src/vs/workbench/services/suggest/browser/media/suggest.css.js +4 -0
- package/vscode/src/vs/workbench/services/suggest/browser/simpleCompletionItem.js +10 -0
- package/vscode/src/vs/workbench/services/suggest/browser/simpleCompletionModel.js +98 -0
- package/vscode/src/vs/workbench/services/suggest/browser/simpleSuggestWidget.js +428 -0
- package/vscode/src/vs/workbench/services/suggest/browser/simpleSuggestWidgetRenderer.js +83 -0
- package/vscode/src/vs/workbench/services/textfile/common/textfiles.js +6 -2
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { DeferredPromise } from 'monaco-editor/esm/vs/base/common/async.js';
|
|
2
|
+
import { VSBuffer } from 'monaco-editor/esm/vs/base/common/buffer.js';
|
|
3
|
+
import { Event, Emitter } from 'monaco-editor/esm/vs/base/common/event.js';
|
|
4
|
+
import { Lazy } from 'monaco-editor/esm/vs/base/common/lazy.js';
|
|
5
|
+
import { Disposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
6
|
+
import { language } from 'monaco-editor/esm/vs/base/common/platform.js';
|
|
7
|
+
import { removeAnsiEscapeCodes } from 'monaco-editor/esm/vs/base/common/strings.js';
|
|
8
|
+
import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
|
|
9
|
+
import { refreshComputedState } from './getComputedState.js';
|
|
10
|
+
import { MutableObservableValue, staticObservableValue } from './observableValue.js';
|
|
11
|
+
import { TestId } from './testId.js';
|
|
12
|
+
import { makeEmptyCounts, terminalStatePriorities, maxPriority, statesInOrder } from './testingStates.js';
|
|
13
|
+
import { TestResultItem, getMarkId } from './testTypes.js';
|
|
14
|
+
const emptyRawOutput = {
|
|
15
|
+
buffers: [],
|
|
16
|
+
length: 0,
|
|
17
|
+
onDidWriteData: Event.None,
|
|
18
|
+
endPromise: Promise.resolve(),
|
|
19
|
+
getRange: () => VSBuffer.alloc(0),
|
|
20
|
+
getRangeIter: () => [],
|
|
21
|
+
};
|
|
22
|
+
class TaskRawOutput {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.writeDataEmitter = ( new Emitter());
|
|
25
|
+
this.endDeferred = ( new DeferredPromise());
|
|
26
|
+
this.offset = 0;
|
|
27
|
+
this.onDidWriteData = this.writeDataEmitter.event;
|
|
28
|
+
this.endPromise = this.endDeferred.p;
|
|
29
|
+
this.buffers = [];
|
|
30
|
+
}
|
|
31
|
+
get length() {
|
|
32
|
+
return this.offset;
|
|
33
|
+
}
|
|
34
|
+
getRange(start, length) {
|
|
35
|
+
const buf = VSBuffer.alloc(length);
|
|
36
|
+
let bufLastWrite = 0;
|
|
37
|
+
for (const chunk of this.getRangeIter(start, length)) {
|
|
38
|
+
buf.buffer.set(chunk.buffer, bufLastWrite);
|
|
39
|
+
bufLastWrite += chunk.byteLength;
|
|
40
|
+
}
|
|
41
|
+
return bufLastWrite < length ? buf.slice(0, bufLastWrite) : buf;
|
|
42
|
+
}
|
|
43
|
+
*getRangeIter(start, length) {
|
|
44
|
+
let soFar = 0;
|
|
45
|
+
let internalLastRead = 0;
|
|
46
|
+
for (const b of this.buffers) {
|
|
47
|
+
if (internalLastRead + b.byteLength <= start) {
|
|
48
|
+
internalLastRead += b.byteLength;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const bstart = Math.max(0, start - internalLastRead);
|
|
52
|
+
const bend = Math.min(b.byteLength, bstart + length - soFar);
|
|
53
|
+
yield b.slice(bstart, bend);
|
|
54
|
+
soFar += bend - bstart;
|
|
55
|
+
internalLastRead += b.byteLength;
|
|
56
|
+
if (soFar === length) {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
append(data, marker) {
|
|
62
|
+
const offset = this.offset;
|
|
63
|
+
let length = data.byteLength;
|
|
64
|
+
if (marker === undefined) {
|
|
65
|
+
this.push(data);
|
|
66
|
+
return { offset, length };
|
|
67
|
+
}
|
|
68
|
+
const start = VSBuffer.fromString(getMarkCode(marker, true));
|
|
69
|
+
const end = VSBuffer.fromString(getMarkCode(marker, false));
|
|
70
|
+
length += start.byteLength + end.byteLength;
|
|
71
|
+
this.push(start);
|
|
72
|
+
let trimLen = data.byteLength;
|
|
73
|
+
for (; trimLen > 0; trimLen--) {
|
|
74
|
+
const last = data.buffer[trimLen - 1];
|
|
75
|
+
if (last !== 13 && last !== 10 ) {
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
this.push(data.slice(0, trimLen));
|
|
80
|
+
this.push(end);
|
|
81
|
+
this.push(data.slice(trimLen));
|
|
82
|
+
return { offset, length };
|
|
83
|
+
}
|
|
84
|
+
push(data) {
|
|
85
|
+
if (data.byteLength === 0) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.buffers.push(data);
|
|
89
|
+
this.writeDataEmitter.fire(data);
|
|
90
|
+
this.offset += data.byteLength;
|
|
91
|
+
}
|
|
92
|
+
end() {
|
|
93
|
+
this.endDeferred.complete();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const resultItemParents = function* (results, item) {
|
|
97
|
+
for (const id of TestId.fromString(item.item.extId).idsToRoot()) {
|
|
98
|
+
yield results.getStateById(( id.toString()));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const maxCountPriority = (counts) => {
|
|
102
|
+
for (const state of statesInOrder) {
|
|
103
|
+
if (counts[state] > 0) {
|
|
104
|
+
return state;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return 0 ;
|
|
108
|
+
};
|
|
109
|
+
const getMarkCode = (marker, start) => `\x1b]633;SetMark;Id=${getMarkId(marker, start)};Hidden\x07`;
|
|
110
|
+
const itemToNode = (controllerId, item, parent) => ({
|
|
111
|
+
controllerId,
|
|
112
|
+
expand: 0 ,
|
|
113
|
+
item: { ...item },
|
|
114
|
+
children: [],
|
|
115
|
+
tasks: [],
|
|
116
|
+
ownComputedState: 0 ,
|
|
117
|
+
computedState: 0 ,
|
|
118
|
+
});
|
|
119
|
+
class LiveTestResult extends Disposable {
|
|
120
|
+
get completedAt() {
|
|
121
|
+
return this._completedAt;
|
|
122
|
+
}
|
|
123
|
+
get tests() {
|
|
124
|
+
return ( this.testById.values());
|
|
125
|
+
}
|
|
126
|
+
constructor(id, persist, request) {
|
|
127
|
+
super();
|
|
128
|
+
this.id = id;
|
|
129
|
+
this.persist = persist;
|
|
130
|
+
this.request = request;
|
|
131
|
+
this.completeEmitter = this._register(( new Emitter()));
|
|
132
|
+
this.newTaskEmitter = this._register(( new Emitter()));
|
|
133
|
+
this.endTaskEmitter = this._register(( new Emitter()));
|
|
134
|
+
this.changeEmitter = this._register(( new Emitter()));
|
|
135
|
+
this.testById = ( new Map());
|
|
136
|
+
this.testMarkerCounter = 0;
|
|
137
|
+
this.startedAt = Date.now();
|
|
138
|
+
this.onChange = this.changeEmitter.event;
|
|
139
|
+
this.onComplete = this.completeEmitter.event;
|
|
140
|
+
this.onNewTask = this.newTaskEmitter.event;
|
|
141
|
+
this.onEndTask = this.endTaskEmitter.event;
|
|
142
|
+
this.tasks = [];
|
|
143
|
+
this.name = ( localizeWithPath(
|
|
144
|
+
'vs/workbench/contrib/testing/common/testResult',
|
|
145
|
+
'runFinished',
|
|
146
|
+
'Test run at {0}',
|
|
147
|
+
( new Date()).toLocaleString(language)
|
|
148
|
+
));
|
|
149
|
+
this.counts = makeEmptyCounts();
|
|
150
|
+
this.computedStateAccessor = {
|
|
151
|
+
getOwnState: i => i.ownComputedState,
|
|
152
|
+
getCurrentComputedState: i => i.computedState,
|
|
153
|
+
setComputedState: (i, s) => i.computedState = s,
|
|
154
|
+
getChildren: i => i.children,
|
|
155
|
+
getParents: i => {
|
|
156
|
+
const { testById: testByExtId } = this;
|
|
157
|
+
return (function* () {
|
|
158
|
+
const parentId = TestId.fromString(i.item.extId).parentId;
|
|
159
|
+
if (parentId) {
|
|
160
|
+
for (const id of parentId.idsToRoot()) {
|
|
161
|
+
yield testByExtId.get(( id.toString()));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})();
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
this.doSerialize = ( new Lazy(() => ({
|
|
168
|
+
id: this.id,
|
|
169
|
+
completedAt: this.completedAt,
|
|
170
|
+
tasks: ( this.tasks.map(t => ({ id: t.id, name: t.name }))),
|
|
171
|
+
name: this.name,
|
|
172
|
+
request: this.request,
|
|
173
|
+
items: ( [...( this.testById.values())].map(TestResultItem.serializeWithoutMessages)),
|
|
174
|
+
})));
|
|
175
|
+
this.doSerializeWithMessages = ( new Lazy(() => ({
|
|
176
|
+
id: this.id,
|
|
177
|
+
completedAt: this.completedAt,
|
|
178
|
+
tasks: ( this.tasks.map(t => ({ id: t.id, name: t.name }))),
|
|
179
|
+
name: this.name,
|
|
180
|
+
request: this.request,
|
|
181
|
+
items: ( [...( this.testById.values())].map(TestResultItem.serialize)),
|
|
182
|
+
})));
|
|
183
|
+
}
|
|
184
|
+
getStateById(extTestId) {
|
|
185
|
+
return this.testById.get(extTestId);
|
|
186
|
+
}
|
|
187
|
+
appendOutput(output, taskId, location, testId) {
|
|
188
|
+
const preview = output.byteLength > 100 ? ( output.slice(0, 100).toString()) + '…' : ( output.toString());
|
|
189
|
+
let marker;
|
|
190
|
+
if (testId || location) {
|
|
191
|
+
marker = this.testMarkerCounter++;
|
|
192
|
+
}
|
|
193
|
+
const index = this.mustGetTaskIndex(taskId);
|
|
194
|
+
const task = this.tasks[index];
|
|
195
|
+
const { offset, length } = task.output.append(output, marker);
|
|
196
|
+
const message = {
|
|
197
|
+
location,
|
|
198
|
+
message: removeAnsiEscapeCodes(preview),
|
|
199
|
+
offset,
|
|
200
|
+
length,
|
|
201
|
+
marker,
|
|
202
|
+
type: 1 ,
|
|
203
|
+
};
|
|
204
|
+
const test = testId && this.testById.get(testId);
|
|
205
|
+
if (test) {
|
|
206
|
+
test.tasks[index].messages.push(message);
|
|
207
|
+
this.changeEmitter.fire({ item: test, result: this, reason: 2 , message });
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
task.otherMessages.push(message);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
addTask(task) {
|
|
214
|
+
this.tasks.push({ ...task, coverage: this._register(( new MutableObservableValue(undefined))), otherMessages: [], output: ( new TaskRawOutput()) });
|
|
215
|
+
for (const test of this.tests) {
|
|
216
|
+
test.tasks.push({ duration: undefined, messages: [], state: 0 });
|
|
217
|
+
}
|
|
218
|
+
this.newTaskEmitter.fire(this.tasks.length - 1);
|
|
219
|
+
}
|
|
220
|
+
addTestChainToRun(controllerId, chain) {
|
|
221
|
+
let parent = this.testById.get(chain[0].extId);
|
|
222
|
+
if (!parent) {
|
|
223
|
+
parent = this.addTestToRun(controllerId, chain[0], null);
|
|
224
|
+
}
|
|
225
|
+
for (let i = 1; i < chain.length; i++) {
|
|
226
|
+
parent = this.addTestToRun(controllerId, chain[i], parent.item.extId);
|
|
227
|
+
}
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
updateState(testId, taskId, state, duration) {
|
|
231
|
+
const entry = this.testById.get(testId);
|
|
232
|
+
if (!entry) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const index = this.mustGetTaskIndex(taskId);
|
|
236
|
+
const oldTerminalStatePrio = terminalStatePriorities[entry.tasks[index].state];
|
|
237
|
+
const newTerminalStatePrio = terminalStatePriorities[state];
|
|
238
|
+
if (oldTerminalStatePrio !== undefined &&
|
|
239
|
+
(newTerminalStatePrio === undefined || newTerminalStatePrio < oldTerminalStatePrio)) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this.fireUpdateAndRefresh(entry, index, state, duration);
|
|
243
|
+
}
|
|
244
|
+
appendMessage(testId, taskId, message) {
|
|
245
|
+
const entry = this.testById.get(testId);
|
|
246
|
+
if (!entry) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
entry.tasks[this.mustGetTaskIndex(taskId)].messages.push(message);
|
|
250
|
+
this.changeEmitter.fire({ item: entry, result: this, reason: 2 , message });
|
|
251
|
+
}
|
|
252
|
+
markTaskComplete(taskId) {
|
|
253
|
+
const index = this.mustGetTaskIndex(taskId);
|
|
254
|
+
const task = this.tasks[index];
|
|
255
|
+
task.running = false;
|
|
256
|
+
task.output.end();
|
|
257
|
+
this.setAllToState(0 , taskId, t => t.state === 1 || t.state === 2 );
|
|
258
|
+
this.endTaskEmitter.fire(index);
|
|
259
|
+
}
|
|
260
|
+
markComplete() {
|
|
261
|
+
if (this._completedAt !== undefined) {
|
|
262
|
+
throw new Error('cannot complete a test result multiple times');
|
|
263
|
+
}
|
|
264
|
+
for (const task of this.tasks) {
|
|
265
|
+
if (task.running) {
|
|
266
|
+
this.markTaskComplete(task.id);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
this._completedAt = Date.now();
|
|
270
|
+
this.completeEmitter.fire();
|
|
271
|
+
}
|
|
272
|
+
markRetired(testIds) {
|
|
273
|
+
for (const [id, test] of this.testById) {
|
|
274
|
+
if (!test.retired && (!testIds || testIds.hasKeyOrParent(TestId.fromString(id).path))) {
|
|
275
|
+
test.retired = true;
|
|
276
|
+
this.changeEmitter.fire({ reason: 0 , item: test, result: this });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
toJSON() {
|
|
281
|
+
return this.completedAt && this.persist ? this.doSerialize.value : undefined;
|
|
282
|
+
}
|
|
283
|
+
toJSONWithMessages() {
|
|
284
|
+
return this.completedAt && this.persist ? this.doSerializeWithMessages.value : undefined;
|
|
285
|
+
}
|
|
286
|
+
setAllToState(state, taskId, when) {
|
|
287
|
+
const index = this.mustGetTaskIndex(taskId);
|
|
288
|
+
for (const test of ( this.testById.values())) {
|
|
289
|
+
if (when(test.tasks[index], test)) {
|
|
290
|
+
this.fireUpdateAndRefresh(test, index, state);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
fireUpdateAndRefresh(entry, taskIndex, newState, newOwnDuration) {
|
|
295
|
+
const previousOwnComputed = entry.ownComputedState;
|
|
296
|
+
const previousOwnDuration = entry.ownDuration;
|
|
297
|
+
const changeEvent = {
|
|
298
|
+
item: entry,
|
|
299
|
+
result: this,
|
|
300
|
+
reason: 1 ,
|
|
301
|
+
previousState: previousOwnComputed,
|
|
302
|
+
previousOwnDuration: previousOwnDuration,
|
|
303
|
+
};
|
|
304
|
+
entry.tasks[taskIndex].state = newState;
|
|
305
|
+
if (newOwnDuration !== undefined) {
|
|
306
|
+
entry.tasks[taskIndex].duration = newOwnDuration;
|
|
307
|
+
entry.ownDuration = Math.max(entry.ownDuration || 0, newOwnDuration);
|
|
308
|
+
}
|
|
309
|
+
const newOwnComputed = maxPriority(...( entry.tasks.map(t => t.state)));
|
|
310
|
+
if (newOwnComputed === previousOwnComputed) {
|
|
311
|
+
if (newOwnDuration !== previousOwnDuration) {
|
|
312
|
+
this.changeEmitter.fire(changeEvent);
|
|
313
|
+
}
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
entry.ownComputedState = newOwnComputed;
|
|
317
|
+
this.counts[previousOwnComputed]--;
|
|
318
|
+
this.counts[newOwnComputed]++;
|
|
319
|
+
refreshComputedState(this.computedStateAccessor, entry).forEach(t => this.changeEmitter.fire(t === entry ? changeEvent : {
|
|
320
|
+
item: t,
|
|
321
|
+
result: this,
|
|
322
|
+
reason: 0 ,
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
addTestToRun(controllerId, item, parent) {
|
|
326
|
+
const node = itemToNode(controllerId, item);
|
|
327
|
+
this.testById.set(item.extId, node);
|
|
328
|
+
this.counts[0 ]++;
|
|
329
|
+
if (parent) {
|
|
330
|
+
this.testById.get(parent)?.children.push(node);
|
|
331
|
+
}
|
|
332
|
+
if (this.tasks.length) {
|
|
333
|
+
for (let i = 0; i < this.tasks.length; i++) {
|
|
334
|
+
node.tasks.push({ duration: undefined, messages: [], state: 0 });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return node;
|
|
338
|
+
}
|
|
339
|
+
mustGetTaskIndex(taskId) {
|
|
340
|
+
const index = this.tasks.findIndex(t => t.id === taskId);
|
|
341
|
+
if (index === -1) {
|
|
342
|
+
throw new Error(`Unknown task ${taskId} in updateState`);
|
|
343
|
+
}
|
|
344
|
+
return index;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
class HydratedTestResult {
|
|
348
|
+
get tests() {
|
|
349
|
+
return ( this.testById.values());
|
|
350
|
+
}
|
|
351
|
+
constructor(serialized, persist = true) {
|
|
352
|
+
this.serialized = serialized;
|
|
353
|
+
this.persist = persist;
|
|
354
|
+
this.counts = makeEmptyCounts();
|
|
355
|
+
this.testById = ( new Map());
|
|
356
|
+
this.id = serialized.id;
|
|
357
|
+
this.completedAt = serialized.completedAt;
|
|
358
|
+
this.tasks = ( serialized.tasks.map((task, i) => ({
|
|
359
|
+
id: task.id,
|
|
360
|
+
name: task.name,
|
|
361
|
+
running: false,
|
|
362
|
+
coverage: staticObservableValue(undefined),
|
|
363
|
+
output: emptyRawOutput,
|
|
364
|
+
otherMessages: []
|
|
365
|
+
})));
|
|
366
|
+
this.name = serialized.name;
|
|
367
|
+
this.request = serialized.request;
|
|
368
|
+
for (const item of serialized.items) {
|
|
369
|
+
const de = TestResultItem.deserialize(item);
|
|
370
|
+
this.counts[de.ownComputedState]++;
|
|
371
|
+
this.testById.set(item.item.extId, de);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
getStateById(extTestId) {
|
|
375
|
+
return this.testById.get(extTestId);
|
|
376
|
+
}
|
|
377
|
+
toJSON() {
|
|
378
|
+
return this.persist ? this.serialized : undefined;
|
|
379
|
+
}
|
|
380
|
+
toJSONWithMessages() {
|
|
381
|
+
return this.toJSON();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
export { HydratedTestResult, LiveTestResult, TaskRawOutput, maxCountPriority, resultItemParents };
|
|
@@ -1,3 +1,158 @@
|
|
|
1
|
+
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import { findFirstIdxMonotonousOrArrLen } from 'monaco-editor/esm/vs/base/common/arraysFind.js';
|
|
3
|
+
import { RunOnceScheduler } from 'monaco-editor/esm/vs/base/common/async.js';
|
|
4
|
+
import { Emitter } from 'monaco-editor/esm/vs/base/common/event.js';
|
|
5
|
+
import { createSingleCallFunction } from 'monaco-editor/esm/vs/base/common/functional.js';
|
|
6
|
+
import { Disposable, toDisposable, dispose, DisposableStore } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
7
|
+
import { generateUuid } from 'monaco-editor/esm/vs/base/common/uuid.js';
|
|
8
|
+
import { IContextKeyService } from 'monaco-editor/esm/vs/platform/contextkey/common/contextkey.js';
|
|
1
9
|
import { createDecorator } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
10
|
+
import { TestingContextKeys } from './testingContextKeys.js';
|
|
11
|
+
import { ITestProfileService } from './testProfileService.js';
|
|
12
|
+
import { LiveTestResult } from './testResult.js';
|
|
13
|
+
import { RETAIN_MAX_RESULTS, ITestResultStorage } from './testResultStorage.js';
|
|
14
|
+
const isRunningTests = (service) => service.results.length > 0 && service.results[0].completedAt === undefined;
|
|
2
15
|
const ITestResultService = ( createDecorator('testResultService'));
|
|
3
|
-
|
|
16
|
+
let TestResultService = class TestResultService extends Disposable {
|
|
17
|
+
get results() {
|
|
18
|
+
this.loadResults();
|
|
19
|
+
return this._results;
|
|
20
|
+
}
|
|
21
|
+
constructor(contextKeyService, storage, testProfiles) {
|
|
22
|
+
super();
|
|
23
|
+
this.storage = storage;
|
|
24
|
+
this.testProfiles = testProfiles;
|
|
25
|
+
this.changeResultEmitter = this._register(( new Emitter()));
|
|
26
|
+
this._results = [];
|
|
27
|
+
this._resultsDisposables = [];
|
|
28
|
+
this.testChangeEmitter = this._register(( new Emitter()));
|
|
29
|
+
this.onResultsChanged = this.changeResultEmitter.event;
|
|
30
|
+
this.onTestChanged = this.testChangeEmitter.event;
|
|
31
|
+
this.loadResults = createSingleCallFunction(() => this.storage.read().then(loaded => {
|
|
32
|
+
for (let i = loaded.length - 1; i >= 0; i--) {
|
|
33
|
+
this.push(loaded[i]);
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
this.persistScheduler = ( new RunOnceScheduler(() => this.persistImmediately(), 500));
|
|
37
|
+
this._register(toDisposable(() => dispose(this._resultsDisposables)));
|
|
38
|
+
this.isRunning = TestingContextKeys.isRunning.bindTo(contextKeyService);
|
|
39
|
+
this.hasAnyResults = TestingContextKeys.hasAnyResults.bindTo(contextKeyService);
|
|
40
|
+
}
|
|
41
|
+
getStateById(extId) {
|
|
42
|
+
for (const result of this.results) {
|
|
43
|
+
const lookup = result.getStateById(extId);
|
|
44
|
+
if (lookup && lookup.computedState !== 0 ) {
|
|
45
|
+
return [result, lookup];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
createLiveResult(req) {
|
|
51
|
+
if ('targets' in req) {
|
|
52
|
+
const id = generateUuid();
|
|
53
|
+
return this.push(( new LiveTestResult(id, true, req)));
|
|
54
|
+
}
|
|
55
|
+
let profile;
|
|
56
|
+
if (req.profile) {
|
|
57
|
+
const profiles = this.testProfiles.getControllerProfiles(req.controllerId);
|
|
58
|
+
profile = profiles.find(c => c.profileId === req.profile.id);
|
|
59
|
+
}
|
|
60
|
+
const resolved = {
|
|
61
|
+
isUiTriggered: false,
|
|
62
|
+
targets: [],
|
|
63
|
+
exclude: req.exclude,
|
|
64
|
+
continuous: req.continuous,
|
|
65
|
+
};
|
|
66
|
+
if (profile) {
|
|
67
|
+
resolved.targets.push({
|
|
68
|
+
profileGroup: profile.group,
|
|
69
|
+
profileId: profile.profileId,
|
|
70
|
+
controllerId: req.controllerId,
|
|
71
|
+
testIds: req.include,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return this.push(( new LiveTestResult(req.id, req.persist, resolved)));
|
|
75
|
+
}
|
|
76
|
+
push(result) {
|
|
77
|
+
if (result.completedAt === undefined) {
|
|
78
|
+
this.results.unshift(result);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const index = findFirstIdxMonotonousOrArrLen(this.results, r => r.completedAt !== undefined && r.completedAt <= result.completedAt);
|
|
82
|
+
this.results.splice(index, 0, result);
|
|
83
|
+
this.persistScheduler.schedule();
|
|
84
|
+
}
|
|
85
|
+
this.hasAnyResults.set(true);
|
|
86
|
+
if (this.results.length > RETAIN_MAX_RESULTS) {
|
|
87
|
+
this.results.pop();
|
|
88
|
+
this._resultsDisposables.pop()?.dispose();
|
|
89
|
+
}
|
|
90
|
+
const ds = ( new DisposableStore());
|
|
91
|
+
this._resultsDisposables.push(ds);
|
|
92
|
+
if (result instanceof LiveTestResult) {
|
|
93
|
+
ds.add(result);
|
|
94
|
+
ds.add(result.onComplete(() => this.onComplete(result)));
|
|
95
|
+
ds.add(result.onChange(this.testChangeEmitter.fire, this.testChangeEmitter));
|
|
96
|
+
this.isRunning.set(true);
|
|
97
|
+
this.changeResultEmitter.fire({ started: result });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.changeResultEmitter.fire({ inserted: result });
|
|
101
|
+
for (const item of result.tests) {
|
|
102
|
+
for (const otherResult of this.results) {
|
|
103
|
+
if (otherResult === result) {
|
|
104
|
+
this.testChangeEmitter.fire({ item, result, reason: 0 });
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
else if (otherResult.getStateById(item.item.extId) !== undefined) {
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
getResult(id) {
|
|
116
|
+
return this.results.find(r => r.id === id);
|
|
117
|
+
}
|
|
118
|
+
clear() {
|
|
119
|
+
const keep = [];
|
|
120
|
+
const removed = [];
|
|
121
|
+
for (const result of this.results) {
|
|
122
|
+
if (result.completedAt !== undefined) {
|
|
123
|
+
removed.push(result);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
keep.push(result);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
this._results = keep;
|
|
130
|
+
this.persistScheduler.schedule();
|
|
131
|
+
if (keep.length === 0) {
|
|
132
|
+
this.hasAnyResults.set(false);
|
|
133
|
+
}
|
|
134
|
+
this.changeResultEmitter.fire({ removed });
|
|
135
|
+
}
|
|
136
|
+
onComplete(result) {
|
|
137
|
+
this.resort();
|
|
138
|
+
this.updateIsRunning();
|
|
139
|
+
this.persistScheduler.schedule();
|
|
140
|
+
this.changeResultEmitter.fire({ completed: result });
|
|
141
|
+
}
|
|
142
|
+
resort() {
|
|
143
|
+
this.results.sort((a, b) => (b.completedAt ?? Number.MAX_SAFE_INTEGER) - (a.completedAt ?? Number.MAX_SAFE_INTEGER));
|
|
144
|
+
}
|
|
145
|
+
updateIsRunning() {
|
|
146
|
+
this.isRunning.set(isRunningTests(this));
|
|
147
|
+
}
|
|
148
|
+
async persistImmediately() {
|
|
149
|
+
await this.loadResults();
|
|
150
|
+
this.storage.persist(this.results);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
TestResultService = ( __decorate([
|
|
154
|
+
( __param(0, IContextKeyService)),
|
|
155
|
+
( __param(1, ITestResultStorage)),
|
|
156
|
+
( __param(2, ITestProfileService))
|
|
157
|
+
], TestResultService));
|
|
158
|
+
export { ITestResultService, TestResultService };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import { VSBuffer, bufferToStream, newWriteableBufferStream } from 'monaco-editor/esm/vs/base/common/buffer.js';
|
|
3
|
+
import { Disposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
4
|
+
import { isDefined } from 'monaco-editor/esm/vs/base/common/types.js';
|
|
5
|
+
import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
|
|
6
|
+
import { IEnvironmentService } from 'monaco-editor/esm/vs/platform/environment/common/environment.js';
|
|
7
|
+
import { IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
|
|
8
|
+
import { createDecorator } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
9
|
+
import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
|
|
10
|
+
import { IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
11
|
+
import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
|
|
12
|
+
import { StoredValue } from './storedValue.js';
|
|
13
|
+
import { HydratedTestResult } from './testResult.js';
|
|
14
|
+
const RETAIN_MAX_RESULTS = 128;
|
|
15
|
+
const RETAIN_MIN_RESULTS = 16;
|
|
16
|
+
const RETAIN_MAX_BYTES = 1024 * 128;
|
|
17
|
+
const CLEANUP_PROBABILITY = 0.2;
|
|
18
|
+
const ITestResultStorage = ( createDecorator('ITestResultStorage'));
|
|
19
|
+
const currentRevision = 1;
|
|
20
|
+
let BaseTestResultStorage = class BaseTestResultStorage extends Disposable {
|
|
21
|
+
constructor(storageService, logService) {
|
|
22
|
+
super();
|
|
23
|
+
this.storageService = storageService;
|
|
24
|
+
this.logService = logService;
|
|
25
|
+
this.stored = this._register(( new StoredValue({
|
|
26
|
+
key: 'storedTestResults',
|
|
27
|
+
scope: 1 ,
|
|
28
|
+
target: 1
|
|
29
|
+
}, this.storageService)));
|
|
30
|
+
}
|
|
31
|
+
async read() {
|
|
32
|
+
const results = await Promise.all(( this.stored.get([]).map(async ({ id, rev }) => {
|
|
33
|
+
if (rev !== currentRevision) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const contents = await this.readForResultId(id);
|
|
38
|
+
if (!contents) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return ( new HydratedTestResult(contents));
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
this.logService.warn(`Error deserializing stored test result ${id}`, e);
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
})));
|
|
48
|
+
return results.filter(isDefined);
|
|
49
|
+
}
|
|
50
|
+
getResultOutputWriter(resultId) {
|
|
51
|
+
const stream = newWriteableBufferStream();
|
|
52
|
+
this.storeOutputForResultId(resultId, stream);
|
|
53
|
+
return stream;
|
|
54
|
+
}
|
|
55
|
+
async persist(results) {
|
|
56
|
+
const toDelete = ( new Map(( this.stored.get([]).map(({ id, bytes }) => [id, bytes]))));
|
|
57
|
+
const toStore = [];
|
|
58
|
+
const todo = [];
|
|
59
|
+
let budget = RETAIN_MAX_BYTES;
|
|
60
|
+
for (let i = 0; i < results.length && i < RETAIN_MAX_RESULTS && (budget > 0 || toStore.length < RETAIN_MIN_RESULTS); i++) {
|
|
61
|
+
const result = results[i];
|
|
62
|
+
const existingBytes = toDelete.get(result.id);
|
|
63
|
+
if (existingBytes !== undefined) {
|
|
64
|
+
toDelete.delete(result.id);
|
|
65
|
+
toStore.push({ id: result.id, rev: currentRevision, bytes: existingBytes });
|
|
66
|
+
budget -= existingBytes;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const obj = result.toJSON();
|
|
70
|
+
if (!obj) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const contents = VSBuffer.fromString(JSON.stringify(obj));
|
|
74
|
+
todo.push(this.storeForResultId(result.id, obj));
|
|
75
|
+
toStore.push({ id: result.id, rev: currentRevision, bytes: contents.byteLength });
|
|
76
|
+
budget -= contents.byteLength;
|
|
77
|
+
}
|
|
78
|
+
for (const id of ( toDelete.keys())) {
|
|
79
|
+
todo.push(this.deleteForResultId(id).catch(() => undefined));
|
|
80
|
+
}
|
|
81
|
+
this.stored.store(toStore);
|
|
82
|
+
await Promise.all(todo);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
BaseTestResultStorage = ( __decorate([
|
|
86
|
+
( __param(0, IStorageService)),
|
|
87
|
+
( __param(1, ILogService))
|
|
88
|
+
], BaseTestResultStorage));
|
|
89
|
+
let TestResultStorage = class TestResultStorage extends BaseTestResultStorage {
|
|
90
|
+
constructor(storageService, logService, workspaceContext, fileService, environmentService) {
|
|
91
|
+
super(storageService, logService);
|
|
92
|
+
this.fileService = fileService;
|
|
93
|
+
this.directory = URI.joinPath(environmentService.workspaceStorageHome, workspaceContext.getWorkspace().id, 'testResults');
|
|
94
|
+
}
|
|
95
|
+
async readForResultId(id) {
|
|
96
|
+
const contents = await this.fileService.readFile(this.getResultJsonPath(id));
|
|
97
|
+
return JSON.parse(( contents.value.toString()));
|
|
98
|
+
}
|
|
99
|
+
storeForResultId(id, contents) {
|
|
100
|
+
return this.fileService.writeFile(this.getResultJsonPath(id), VSBuffer.fromString(JSON.stringify(contents)));
|
|
101
|
+
}
|
|
102
|
+
deleteForResultId(id) {
|
|
103
|
+
return this.fileService.del(this.getResultJsonPath(id)).catch(() => undefined);
|
|
104
|
+
}
|
|
105
|
+
async readOutputRangeForResultId(id, offset, length) {
|
|
106
|
+
try {
|
|
107
|
+
const { value } = await this.fileService.readFile(this.getResultOutputPath(id), { position: offset, length });
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return VSBuffer.alloc(0);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async readOutputForResultId(id) {
|
|
115
|
+
try {
|
|
116
|
+
const { value } = await this.fileService.readFileStream(this.getResultOutputPath(id));
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return bufferToStream(VSBuffer.alloc(0));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async storeOutputForResultId(id, input) {
|
|
124
|
+
await this.fileService.createFile(this.getResultOutputPath(id), input);
|
|
125
|
+
}
|
|
126
|
+
async persist(results) {
|
|
127
|
+
await super.persist(results);
|
|
128
|
+
if (Math.random() < CLEANUP_PROBABILITY) {
|
|
129
|
+
await this.cleanupDereferenced();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async cleanupDereferenced() {
|
|
133
|
+
const { children } = await this.fileService.resolve(this.directory);
|
|
134
|
+
if (!children) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const stored = ( new Set(( this.stored.get([]).filter(s => s.rev === currentRevision).map(s => s.id))));
|
|
138
|
+
await Promise.all(( children
|
|
139
|
+
.filter(child => !( stored.has(child.name.replace(/\.[a-z]+$/, ''))))
|
|
140
|
+
.map(child => this.fileService.del(child.resource).catch(() => undefined))));
|
|
141
|
+
}
|
|
142
|
+
getResultJsonPath(id) {
|
|
143
|
+
return URI.joinPath(this.directory, `${id}.json`);
|
|
144
|
+
}
|
|
145
|
+
getResultOutputPath(id) {
|
|
146
|
+
return URI.joinPath(this.directory, `${id}.output`);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
TestResultStorage = ( __decorate([
|
|
150
|
+
( __param(0, IStorageService)),
|
|
151
|
+
( __param(1, ILogService)),
|
|
152
|
+
( __param(2, IWorkspaceContextService)),
|
|
153
|
+
( __param(3, IFileService)),
|
|
154
|
+
( __param(4, IEnvironmentService))
|
|
155
|
+
], TestResultStorage));
|
|
156
|
+
export { BaseTestResultStorage, ITestResultStorage, RETAIN_MAX_RESULTS, TestResultStorage };
|