@codingame/monaco-vscode-working-copy-service-override 1.83.13

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.
@@ -0,0 +1,11 @@
1
+ function __decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function __param(paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ }
10
+
11
+ export { __decorate, __param };
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from './workingCopy.js';
package/index.js ADDED
@@ -0,0 +1 @@
1
+ export { default } from './workingCopy.js';
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@codingame/monaco-vscode-working-copy-service-override",
3
+ "version": "1.83.13",
4
+ "keywords": [],
5
+ "author": {
6
+ "name": "CodinGame",
7
+ "url": "http://www.codingame.com"
8
+ },
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/CodinGame/monaco-vscode-api.git"
13
+ },
14
+ "type": "module",
15
+ "private": false,
16
+ "description": "VSCode public API plugged on the monaco editor - working-copy service-override",
17
+ "main": "index.js",
18
+ "module": "index.js",
19
+ "types": "index.d.ts",
20
+ "dependencies": {
21
+ "vscode": "npm:@codingame/monaco-vscode-api@1.83.13",
22
+ "monaco-editor": "0.44.0",
23
+ "@codingame/monaco-vscode-files-service-override": "1.83.13"
24
+ }
25
+ }
@@ -0,0 +1,25 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import { IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
3
+ import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService';
4
+ import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
5
+ import { WorkingCopyBackupService } from '../common/workingCopyBackupService.js';
6
+ import { joinPath } from 'monaco-editor/esm/vs/base/common/resources.js';
7
+ import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
8
+ import { Registry } from 'monaco-editor/esm/vs/platform/registry/common/platform.js';
9
+ import { Extensions } from 'vscode/vscode/vs/workbench/common/contributions';
10
+ import { BrowserWorkingCopyBackupTracker } from './workingCopyBackupTracker.js';
11
+
12
+ let BrowserWorkingCopyBackupService = class BrowserWorkingCopyBackupService extends WorkingCopyBackupService {
13
+ constructor(contextService, environmentService, fileService, logService) {
14
+ super(joinPath(environmentService.userRoamingDataHome, 'Backups', contextService.getWorkspace().id), fileService, logService);
15
+ }
16
+ };
17
+ BrowserWorkingCopyBackupService = ( __decorate([
18
+ ( __param(0, IWorkspaceContextService)),
19
+ ( __param(1, IWorkbenchEnvironmentService)),
20
+ ( __param(2, IFileService)),
21
+ ( __param(3, ILogService))
22
+ ], BrowserWorkingCopyBackupService));
23
+ ( Registry.as(Extensions.Workbench)).registerWorkbenchContribution(BrowserWorkingCopyBackupTracker, 1 );
24
+
25
+ export { BrowserWorkingCopyBackupService };
@@ -0,0 +1,44 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import { IWorkingCopyBackupService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyBackup';
3
+ import { IFilesConfigurationService } from 'vscode/vscode/vs/workbench/services/filesConfiguration/common/filesConfigurationService';
4
+ import { IWorkingCopyService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyService';
5
+ import { ILifecycleService } from 'vscode/vscode/vs/workbench/services/lifecycle/common/lifecycle';
6
+ import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
7
+ import { WorkingCopyBackupTracker } from '../common/workingCopyBackupTracker.js';
8
+ import { IWorkingCopyEditorService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyEditorService';
9
+ import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService';
10
+ import { IEditorGroupsService } from 'vscode/vscode/vs/workbench/services/editor/common/editorGroupsService';
11
+
12
+ let BrowserWorkingCopyBackupTracker = class BrowserWorkingCopyBackupTracker extends WorkingCopyBackupTracker {
13
+ constructor(workingCopyBackupService, filesConfigurationService, workingCopyService, lifecycleService, logService, workingCopyEditorService, editorService, editorGroupService) {
14
+ super(workingCopyBackupService, workingCopyService, logService, lifecycleService, filesConfigurationService, workingCopyEditorService, editorService, editorGroupService);
15
+ }
16
+ onFinalBeforeShutdown(reason) {
17
+ const modifiedWorkingCopies = this.workingCopyService.modifiedWorkingCopies;
18
+ if (!modifiedWorkingCopies.length) {
19
+ return false;
20
+ }
21
+ if (!this.filesConfigurationService.isHotExitEnabled) {
22
+ return true;
23
+ }
24
+ for (const modifiedWorkingCopy of modifiedWorkingCopies) {
25
+ if (!this.workingCopyBackupService.hasBackupSync(modifiedWorkingCopy, this.getContentVersion(modifiedWorkingCopy))) {
26
+ this.logService.warn('Unload veto: pending backups');
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ }
32
+ };
33
+ BrowserWorkingCopyBackupTracker = ( __decorate([
34
+ ( __param(0, IWorkingCopyBackupService)),
35
+ ( __param(1, IFilesConfigurationService)),
36
+ ( __param(2, IWorkingCopyService)),
37
+ ( __param(3, ILifecycleService)),
38
+ ( __param(4, ILogService)),
39
+ ( __param(5, IWorkingCopyEditorService)),
40
+ ( __param(6, IEditorService)),
41
+ ( __param(7, IEditorGroupsService))
42
+ ], BrowserWorkingCopyBackupTracker));
43
+
44
+ export { BrowserWorkingCopyBackupTracker };
@@ -0,0 +1,454 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import { joinPath } from 'monaco-editor/esm/vs/base/common/resources.js';
3
+ import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
4
+ import { coalesce } from 'monaco-editor/esm/vs/base/common/arrays.js';
5
+ import { deepClone, equals } from 'monaco-editor/esm/vs/base/common/objects.js';
6
+ import { ResourceQueue, Promises } from 'monaco-editor/esm/vs/base/common/async.js';
7
+ import { IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
8
+ import { ResourceMap } from 'monaco-editor/esm/vs/base/common/map.js';
9
+ import { isReadableStream, peekStream } from 'monaco-editor/esm/vs/base/common/stream.js';
10
+ import { VSBuffer, prefixedBufferStream, prefixedBufferReadable, bufferToStream, streamToBuffer, readableToBuffer } from 'monaco-editor/esm/vs/base/common/buffer.js';
11
+ import { Disposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
12
+ import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
13
+ import { Schemas } from 'monaco-editor/esm/vs/base/common/network.js';
14
+ import { hash } from 'monaco-editor/esm/vs/base/common/hash.js';
15
+ import { isEmptyObject } from 'monaco-editor/esm/vs/base/common/types.js';
16
+ import { NO_TYPE_ID } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopy';
17
+
18
+ var WorkingCopyBackupServiceImpl_1;
19
+ class WorkingCopyBackupsModel {
20
+ static async create(backupRoot, fileService) {
21
+ const model = ( new WorkingCopyBackupsModel(backupRoot, fileService));
22
+ await model.resolve();
23
+ return model;
24
+ }
25
+ constructor(backupRoot, fileService) {
26
+ this.backupRoot = backupRoot;
27
+ this.fileService = fileService;
28
+ this.cache = ( new ResourceMap());
29
+ }
30
+ async resolve() {
31
+ try {
32
+ const backupRootStat = await this.fileService.resolve(this.backupRoot);
33
+ if (backupRootStat.children) {
34
+ await Promises.settled(( backupRootStat.children
35
+ .filter(child => child.isDirectory)
36
+ .map(async (backupSchemaFolder) => {
37
+ const backupSchemaFolderStat = await this.fileService.resolve(backupSchemaFolder.resource);
38
+ if (backupSchemaFolderStat.children) {
39
+ for (const backupForSchema of backupSchemaFolderStat.children) {
40
+ if (!backupForSchema.isDirectory) {
41
+ this.add(backupForSchema.resource);
42
+ }
43
+ }
44
+ }
45
+ })));
46
+ }
47
+ }
48
+ catch (error) {
49
+ }
50
+ }
51
+ add(resource, versionId = 0, meta) {
52
+ this.cache.set(resource, {
53
+ versionId,
54
+ meta: deepClone(meta)
55
+ });
56
+ }
57
+ update(resource, meta) {
58
+ const entry = this.cache.get(resource);
59
+ if (entry) {
60
+ entry.meta = deepClone(meta);
61
+ }
62
+ }
63
+ count() {
64
+ return this.cache.size;
65
+ }
66
+ has(resource, versionId, meta) {
67
+ const entry = this.cache.get(resource);
68
+ if (!entry) {
69
+ return false;
70
+ }
71
+ if (typeof versionId === 'number' && versionId !== entry.versionId) {
72
+ return false;
73
+ }
74
+ if (meta && !equals(meta, entry.meta)) {
75
+ return false;
76
+ }
77
+ return true;
78
+ }
79
+ get() {
80
+ return Array.from(( this.cache.keys()));
81
+ }
82
+ remove(resource) {
83
+ this.cache.delete(resource);
84
+ }
85
+ clear() {
86
+ this.cache.clear();
87
+ }
88
+ }
89
+ let WorkingCopyBackupService = class WorkingCopyBackupService extends Disposable {
90
+ constructor(backupWorkspaceHome, fileService, logService) {
91
+ super();
92
+ this.fileService = fileService;
93
+ this.logService = logService;
94
+ this.impl = this._register(this.initialize(backupWorkspaceHome));
95
+ }
96
+ initialize(backupWorkspaceHome) {
97
+ if (backupWorkspaceHome) {
98
+ return ( new WorkingCopyBackupServiceImpl(backupWorkspaceHome, this.fileService, this.logService));
99
+ }
100
+ return ( new InMemoryWorkingCopyBackupService());
101
+ }
102
+ reinitialize(backupWorkspaceHome) {
103
+ if (this.impl instanceof WorkingCopyBackupServiceImpl) {
104
+ if (backupWorkspaceHome) {
105
+ this.impl.initialize(backupWorkspaceHome);
106
+ }
107
+ else {
108
+ this.impl = ( new InMemoryWorkingCopyBackupService());
109
+ }
110
+ }
111
+ }
112
+ hasBackups() {
113
+ return this.impl.hasBackups();
114
+ }
115
+ hasBackupSync(identifier, versionId, meta) {
116
+ return this.impl.hasBackupSync(identifier, versionId, meta);
117
+ }
118
+ backup(identifier, content, versionId, meta, token) {
119
+ return this.impl.backup(identifier, content, versionId, meta, token);
120
+ }
121
+ discardBackup(identifier, token) {
122
+ return this.impl.discardBackup(identifier, token);
123
+ }
124
+ discardBackups(filter) {
125
+ return this.impl.discardBackups(filter);
126
+ }
127
+ getBackups() {
128
+ return this.impl.getBackups();
129
+ }
130
+ resolve(identifier) {
131
+ return this.impl.resolve(identifier);
132
+ }
133
+ toBackupResource(identifier) {
134
+ return this.impl.toBackupResource(identifier);
135
+ }
136
+ joinBackups() {
137
+ return this.impl.joinBackups();
138
+ }
139
+ };
140
+ WorkingCopyBackupService = ( __decorate([
141
+ ( __param(1, IFileService)),
142
+ ( __param(2, ILogService))
143
+ ], WorkingCopyBackupService));
144
+ let WorkingCopyBackupServiceImpl = class WorkingCopyBackupServiceImpl extends Disposable {
145
+ static { WorkingCopyBackupServiceImpl_1 = this; }
146
+ static { this.PREAMBLE_END_MARKER = '\n'; }
147
+ static { this.PREAMBLE_END_MARKER_CHARCODE = '\n'.charCodeAt(0); }
148
+ static { this.PREAMBLE_META_SEPARATOR = ' '; }
149
+ static { this.PREAMBLE_MAX_LENGTH = 10000; }
150
+ constructor(backupWorkspaceHome, fileService, logService) {
151
+ super();
152
+ this.backupWorkspaceHome = backupWorkspaceHome;
153
+ this.fileService = fileService;
154
+ this.logService = logService;
155
+ this.ioOperationQueues = this._register(( new ResourceQueue()));
156
+ this.model = undefined;
157
+ this.initialize(backupWorkspaceHome);
158
+ }
159
+ initialize(backupWorkspaceResource) {
160
+ this.backupWorkspaceHome = backupWorkspaceResource;
161
+ this.ready = this.doInitialize();
162
+ }
163
+ async doInitialize() {
164
+ this.model = await WorkingCopyBackupsModel.create(this.backupWorkspaceHome, this.fileService);
165
+ return this.model;
166
+ }
167
+ async hasBackups() {
168
+ const model = await this.ready;
169
+ await this.joinBackups();
170
+ return model.count() > 0;
171
+ }
172
+ hasBackupSync(identifier, versionId, meta) {
173
+ if (!this.model) {
174
+ return false;
175
+ }
176
+ const backupResource = this.toBackupResource(identifier);
177
+ return ( this.model.has(backupResource, versionId, meta));
178
+ }
179
+ async backup(identifier, content, versionId, meta, token) {
180
+ const model = await this.ready;
181
+ if (token?.isCancellationRequested) {
182
+ return;
183
+ }
184
+ const backupResource = this.toBackupResource(identifier);
185
+ if (( model.has(backupResource, versionId, meta))) {
186
+ return;
187
+ }
188
+ return this.ioOperationQueues.queueFor(backupResource).queue(async () => {
189
+ if (token?.isCancellationRequested) {
190
+ return;
191
+ }
192
+ if (( model.has(backupResource, versionId, meta))) {
193
+ return;
194
+ }
195
+ let preamble = this.createPreamble(identifier, meta);
196
+ if (preamble.length >= WorkingCopyBackupServiceImpl_1.PREAMBLE_MAX_LENGTH) {
197
+ preamble = this.createPreamble(identifier);
198
+ }
199
+ const preambleBuffer = VSBuffer.fromString(preamble);
200
+ let backupBuffer;
201
+ if (isReadableStream(content)) {
202
+ backupBuffer = prefixedBufferStream(preambleBuffer, content);
203
+ }
204
+ else if (content) {
205
+ backupBuffer = prefixedBufferReadable(preambleBuffer, content);
206
+ }
207
+ else {
208
+ backupBuffer = VSBuffer.concat([preambleBuffer, VSBuffer.fromString('')]);
209
+ }
210
+ await this.fileService.writeFile(backupResource, backupBuffer);
211
+ model.add(backupResource, versionId, meta);
212
+ });
213
+ }
214
+ createPreamble(identifier, meta) {
215
+ return `${( identifier.resource.toString())}${WorkingCopyBackupServiceImpl_1.PREAMBLE_META_SEPARATOR}${JSON.stringify({ ...meta, typeId: identifier.typeId })}${WorkingCopyBackupServiceImpl_1.PREAMBLE_END_MARKER}`;
216
+ }
217
+ async discardBackups(filter) {
218
+ const model = await this.ready;
219
+ const except = filter?.except;
220
+ if (Array.isArray(except) && except.length > 0) {
221
+ const exceptMap = ( new ResourceMap());
222
+ for (const exceptWorkingCopy of except) {
223
+ exceptMap.set(this.toBackupResource(exceptWorkingCopy), true);
224
+ }
225
+ await Promises.settled(( model.get().map(async (backupResource) => {
226
+ if (!( exceptMap.has(backupResource))) {
227
+ await this.doDiscardBackup(backupResource);
228
+ }
229
+ })));
230
+ }
231
+ else {
232
+ await this.deleteIgnoreFileNotFound(this.backupWorkspaceHome);
233
+ model.clear();
234
+ }
235
+ }
236
+ discardBackup(identifier, token) {
237
+ const backupResource = this.toBackupResource(identifier);
238
+ return this.doDiscardBackup(backupResource, token);
239
+ }
240
+ async doDiscardBackup(backupResource, token) {
241
+ const model = await this.ready;
242
+ if (token?.isCancellationRequested) {
243
+ return;
244
+ }
245
+ return this.ioOperationQueues.queueFor(backupResource).queue(async () => {
246
+ if (token?.isCancellationRequested) {
247
+ return;
248
+ }
249
+ await this.deleteIgnoreFileNotFound(backupResource);
250
+ model.remove(backupResource);
251
+ });
252
+ }
253
+ async deleteIgnoreFileNotFound(backupResource) {
254
+ try {
255
+ await this.fileService.del(backupResource, { recursive: true });
256
+ }
257
+ catch (error) {
258
+ if (error.fileOperationResult !== 1 ) {
259
+ throw error;
260
+ }
261
+ }
262
+ }
263
+ async getBackups() {
264
+ const model = await this.ready;
265
+ await this.joinBackups();
266
+ const backups = await Promise.all(( model.get().map(backupResource => this.resolveIdentifier(backupResource, model))));
267
+ return coalesce(backups);
268
+ }
269
+ async resolveIdentifier(backupResource, model) {
270
+ let res = undefined;
271
+ await this.ioOperationQueues.queueFor(backupResource).queue(async () => {
272
+ if (!( model.has(backupResource))) {
273
+ return;
274
+ }
275
+ const backupPreamble = await this.readToMatchingString(backupResource, WorkingCopyBackupServiceImpl_1.PREAMBLE_END_MARKER, WorkingCopyBackupServiceImpl_1.PREAMBLE_MAX_LENGTH);
276
+ if (!backupPreamble) {
277
+ return;
278
+ }
279
+ const metaStartIndex = backupPreamble.indexOf(WorkingCopyBackupServiceImpl_1.PREAMBLE_META_SEPARATOR);
280
+ let resourcePreamble;
281
+ let metaPreamble;
282
+ if (metaStartIndex > 0) {
283
+ resourcePreamble = backupPreamble.substring(0, metaStartIndex);
284
+ metaPreamble = backupPreamble.substr(metaStartIndex + 1);
285
+ }
286
+ else {
287
+ resourcePreamble = backupPreamble;
288
+ metaPreamble = undefined;
289
+ }
290
+ const { typeId, meta } = this.parsePreambleMeta(metaPreamble);
291
+ model.update(backupResource, meta);
292
+ res = {
293
+ typeId: typeId ?? NO_TYPE_ID,
294
+ resource: ( URI.parse(resourcePreamble))
295
+ };
296
+ });
297
+ return res;
298
+ }
299
+ async readToMatchingString(backupResource, matchingString, maximumBytesToRead) {
300
+ const contents = ( (await this.fileService.readFile(backupResource, { length: maximumBytesToRead })).value.toString());
301
+ const matchingStringIndex = contents.indexOf(matchingString);
302
+ if (matchingStringIndex >= 0) {
303
+ return contents.substr(0, matchingStringIndex);
304
+ }
305
+ return undefined;
306
+ }
307
+ async resolve(identifier) {
308
+ const backupResource = this.toBackupResource(identifier);
309
+ const model = await this.ready;
310
+ let res = undefined;
311
+ await this.ioOperationQueues.queueFor(backupResource).queue(async () => {
312
+ if (!( model.has(backupResource))) {
313
+ return;
314
+ }
315
+ const backupStream = await this.fileService.readFileStream(backupResource);
316
+ const peekedBackupStream = await peekStream(backupStream.value, 1);
317
+ const firstBackupChunk = VSBuffer.concat(peekedBackupStream.buffer);
318
+ const preambleEndIndex = firstBackupChunk.buffer.indexOf(WorkingCopyBackupServiceImpl_1.PREAMBLE_END_MARKER_CHARCODE);
319
+ if (preambleEndIndex === -1) {
320
+ this.logService.trace(`Backup: Could not find meta end marker in ${backupResource}. The file is probably corrupt (filesize: ${backupStream.size}).`);
321
+ return undefined;
322
+ }
323
+ const preambelRaw = ( firstBackupChunk.slice(0, preambleEndIndex).toString());
324
+ let meta;
325
+ const metaStartIndex = preambelRaw.indexOf(WorkingCopyBackupServiceImpl_1.PREAMBLE_META_SEPARATOR);
326
+ if (metaStartIndex !== -1) {
327
+ meta = this.parsePreambleMeta(preambelRaw.substr(metaStartIndex + 1)).meta;
328
+ }
329
+ model.update(backupResource, meta);
330
+ const firstBackupChunkWithoutPreamble = firstBackupChunk.slice(preambleEndIndex + 1);
331
+ let value;
332
+ if (peekedBackupStream.ended) {
333
+ value = bufferToStream(firstBackupChunkWithoutPreamble);
334
+ }
335
+ else {
336
+ value = prefixedBufferStream(firstBackupChunkWithoutPreamble, peekedBackupStream.stream);
337
+ }
338
+ res = { value, meta };
339
+ });
340
+ return res;
341
+ }
342
+ parsePreambleMeta(preambleMetaRaw) {
343
+ let typeId = undefined;
344
+ let meta = undefined;
345
+ if (preambleMetaRaw) {
346
+ try {
347
+ meta = JSON.parse(preambleMetaRaw);
348
+ typeId = meta?.typeId;
349
+ if (typeof meta?.typeId === 'string') {
350
+ delete meta.typeId;
351
+ if (isEmptyObject(meta)) {
352
+ meta = undefined;
353
+ }
354
+ }
355
+ }
356
+ catch (error) {
357
+ }
358
+ }
359
+ return { typeId, meta };
360
+ }
361
+ toBackupResource(identifier) {
362
+ return joinPath(this.backupWorkspaceHome, identifier.resource.scheme, hashIdentifier(identifier));
363
+ }
364
+ joinBackups() {
365
+ return this.ioOperationQueues.whenDrained();
366
+ }
367
+ };
368
+ WorkingCopyBackupServiceImpl = WorkingCopyBackupServiceImpl_1 = ( __decorate([
369
+ ( __param(1, IFileService)),
370
+ ( __param(2, ILogService))
371
+ ], WorkingCopyBackupServiceImpl));
372
+ class InMemoryWorkingCopyBackupService extends Disposable {
373
+ constructor() {
374
+ super();
375
+ this.backups = ( new ResourceMap());
376
+ }
377
+ async hasBackups() {
378
+ return this.backups.size > 0;
379
+ }
380
+ hasBackupSync(identifier, versionId) {
381
+ const backupResource = this.toBackupResource(identifier);
382
+ return ( this.backups.has(backupResource));
383
+ }
384
+ async backup(identifier, content, versionId, meta, token) {
385
+ const backupResource = this.toBackupResource(identifier);
386
+ this.backups.set(backupResource, {
387
+ typeId: identifier.typeId,
388
+ content: content instanceof VSBuffer ? content : content ? isReadableStream(content) ? await streamToBuffer(content) : readableToBuffer(content) : VSBuffer.fromString(''),
389
+ meta
390
+ });
391
+ }
392
+ async resolve(identifier) {
393
+ const backupResource = this.toBackupResource(identifier);
394
+ const backup = this.backups.get(backupResource);
395
+ if (backup) {
396
+ return { value: bufferToStream(backup.content), meta: backup.meta };
397
+ }
398
+ return undefined;
399
+ }
400
+ async getBackups() {
401
+ return ( Array.from(this.backups.entries()).map(([resource, backup]) => ({ typeId: backup.typeId, resource })));
402
+ }
403
+ async discardBackup(identifier) {
404
+ this.backups.delete(this.toBackupResource(identifier));
405
+ }
406
+ async discardBackups(filter) {
407
+ const except = filter?.except;
408
+ if (Array.isArray(except) && except.length > 0) {
409
+ const exceptMap = ( new ResourceMap());
410
+ for (const exceptWorkingCopy of except) {
411
+ exceptMap.set(this.toBackupResource(exceptWorkingCopy), true);
412
+ }
413
+ for (const backup of await this.getBackups()) {
414
+ if (!( exceptMap.has(this.toBackupResource(backup)))) {
415
+ await this.discardBackup(backup);
416
+ }
417
+ }
418
+ }
419
+ else {
420
+ this.backups.clear();
421
+ }
422
+ }
423
+ toBackupResource(identifier) {
424
+ return ( URI.from({ scheme: Schemas.inMemory, path: hashIdentifier(identifier) }));
425
+ }
426
+ async joinBackups() {
427
+ return;
428
+ }
429
+ }
430
+ function hashIdentifier(identifier) {
431
+ let resource;
432
+ if (identifier.typeId.length > 0) {
433
+ const typeIdHash = hashString(identifier.typeId);
434
+ if (identifier.resource.path) {
435
+ resource = joinPath(identifier.resource, typeIdHash);
436
+ }
437
+ else {
438
+ resource = identifier.resource.with({ path: typeIdHash });
439
+ }
440
+ }
441
+ else {
442
+ resource = identifier.resource;
443
+ }
444
+ return hashPath(resource);
445
+ }
446
+ function hashPath(resource) {
447
+ const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : ( resource.toString());
448
+ return hashString(str);
449
+ }
450
+ function hashString(str) {
451
+ return ( hash(str).toString(16));
452
+ }
453
+
454
+ export { InMemoryWorkingCopyBackupService, WorkingCopyBackupService, WorkingCopyBackupsModel, hashIdentifier };
@@ -0,0 +1,255 @@
1
+ import { Disposable, toDisposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
2
+ import { CancellationTokenSource } from 'monaco-editor/esm/vs/base/common/cancellation.js';
3
+ import { Promises } from 'monaco-editor/esm/vs/base/common/async.js';
4
+
5
+ class WorkingCopyBackupTracker extends Disposable {
6
+ constructor(workingCopyBackupService, workingCopyService, logService, lifecycleService, filesConfigurationService, workingCopyEditorService, editorService, editorGroupService) {
7
+ super();
8
+ this.workingCopyBackupService = workingCopyBackupService;
9
+ this.workingCopyService = workingCopyService;
10
+ this.logService = logService;
11
+ this.lifecycleService = lifecycleService;
12
+ this.filesConfigurationService = filesConfigurationService;
13
+ this.workingCopyEditorService = workingCopyEditorService;
14
+ this.editorService = editorService;
15
+ this.editorGroupService = editorGroupService;
16
+ this.mapWorkingCopyToContentVersion = ( new Map());
17
+ this.pendingBackupOperations = ( new Map());
18
+ this.suspended = false;
19
+ this.unrestoredBackups = ( new Set());
20
+ this.whenReady = this.resolveBackupsToRestore();
21
+ this._isReady = false;
22
+ for (const workingCopy of this.workingCopyService.modifiedWorkingCopies) {
23
+ this.onDidRegister(workingCopy);
24
+ }
25
+ this.registerListeners();
26
+ }
27
+ registerListeners() {
28
+ this._register(this.workingCopyService.onDidRegister(workingCopy => this.onDidRegister(workingCopy)));
29
+ this._register(this.workingCopyService.onDidUnregister(workingCopy => this.onDidUnregister(workingCopy)));
30
+ this._register(this.workingCopyService.onDidChangeDirty(workingCopy => this.onDidChangeDirty(workingCopy)));
31
+ this._register(this.workingCopyService.onDidChangeContent(workingCopy => this.onDidChangeContent(workingCopy)));
32
+ this._register(this.lifecycleService.onBeforeShutdown(event => event.finalVeto(() => this.onFinalBeforeShutdown(event.reason), 'veto.backups')));
33
+ this._register(this.lifecycleService.onWillShutdown(() => this.onWillShutdown()));
34
+ this._register(this.workingCopyEditorService.onDidRegisterHandler(handler => this.restoreBackups(handler)));
35
+ }
36
+ onWillShutdown() {
37
+ this.cancelBackupOperations();
38
+ this.suspendBackupOperations();
39
+ }
40
+ static { this.DEFAULT_BACKUP_SCHEDULE_DELAYS = {
41
+ [0 ]: 1000,
42
+ [3 ]: 1000,
43
+ [4 ]: 1000,
44
+ [1 ]: 2000,
45
+ [2 ]: 1000
46
+ }; }
47
+ onDidRegister(workingCopy) {
48
+ if (this.suspended) {
49
+ this.logService.warn(`[backup tracker] suspended, ignoring register event`, ( workingCopy.resource.toString()), workingCopy.typeId);
50
+ return;
51
+ }
52
+ if (workingCopy.isModified()) {
53
+ this.scheduleBackup(workingCopy);
54
+ }
55
+ }
56
+ onDidUnregister(workingCopy) {
57
+ this.mapWorkingCopyToContentVersion.delete(workingCopy);
58
+ if (this.suspended) {
59
+ this.logService.warn(`[backup tracker] suspended, ignoring unregister event`, ( workingCopy.resource.toString()), workingCopy.typeId);
60
+ return;
61
+ }
62
+ this.discardBackup(workingCopy);
63
+ }
64
+ onDidChangeDirty(workingCopy) {
65
+ if (this.suspended) {
66
+ this.logService.warn(`[backup tracker] suspended, ignoring dirty change event`, ( workingCopy.resource.toString()), workingCopy.typeId);
67
+ return;
68
+ }
69
+ if (workingCopy.isDirty()) {
70
+ this.scheduleBackup(workingCopy);
71
+ }
72
+ else {
73
+ this.discardBackup(workingCopy);
74
+ }
75
+ }
76
+ onDidChangeContent(workingCopy) {
77
+ const contentVersionId = this.getContentVersion(workingCopy);
78
+ this.mapWorkingCopyToContentVersion.set(workingCopy, contentVersionId + 1);
79
+ if (this.suspended) {
80
+ this.logService.warn(`[backup tracker] suspended, ignoring content change event`, ( workingCopy.resource.toString()), workingCopy.typeId);
81
+ return;
82
+ }
83
+ if (workingCopy.isModified()) {
84
+ this.scheduleBackup(workingCopy);
85
+ }
86
+ }
87
+ scheduleBackup(workingCopy) {
88
+ this.cancelBackupOperation(workingCopy);
89
+ this.logService.trace(`[backup tracker] scheduling backup`, ( workingCopy.resource.toString()), workingCopy.typeId);
90
+ const workingCopyIdentifier = { resource: workingCopy.resource, typeId: workingCopy.typeId };
91
+ const cts = ( new CancellationTokenSource());
92
+ const handle = setTimeout(async () => {
93
+ if (cts.token.isCancellationRequested) {
94
+ return;
95
+ }
96
+ if (workingCopy.isModified()) {
97
+ this.logService.trace(`[backup tracker] creating backup`, ( workingCopy.resource.toString()), workingCopy.typeId);
98
+ try {
99
+ const backup = await workingCopy.backup(cts.token);
100
+ if (cts.token.isCancellationRequested) {
101
+ return;
102
+ }
103
+ if (workingCopy.isModified()) {
104
+ this.logService.trace(`[backup tracker] storing backup`, ( workingCopy.resource.toString()), workingCopy.typeId);
105
+ await this.workingCopyBackupService.backup(workingCopy, backup.content, this.getContentVersion(workingCopy), backup.meta, cts.token);
106
+ }
107
+ }
108
+ catch (error) {
109
+ this.logService.error(error);
110
+ }
111
+ }
112
+ if (!cts.token.isCancellationRequested) {
113
+ this.doClearPendingBackupOperation(workingCopyIdentifier);
114
+ }
115
+ }, this.getBackupScheduleDelay(workingCopy));
116
+ this.pendingBackupOperations.set(workingCopyIdentifier, {
117
+ cancel: () => {
118
+ this.logService.trace(`[backup tracker] clearing pending backup creation`, ( workingCopy.resource.toString()), workingCopy.typeId);
119
+ cts.cancel();
120
+ },
121
+ disposable: toDisposable(() => {
122
+ cts.dispose();
123
+ clearTimeout(handle);
124
+ })
125
+ });
126
+ }
127
+ getBackupScheduleDelay(workingCopy) {
128
+ if (typeof workingCopy.backupDelay === 'number') {
129
+ return workingCopy.backupDelay;
130
+ }
131
+ let autoSaveMode = this.filesConfigurationService.getAutoSaveMode();
132
+ if (workingCopy.capabilities & 2 ) {
133
+ autoSaveMode = 0 ;
134
+ }
135
+ return WorkingCopyBackupTracker.DEFAULT_BACKUP_SCHEDULE_DELAYS[autoSaveMode];
136
+ }
137
+ getContentVersion(workingCopy) {
138
+ return this.mapWorkingCopyToContentVersion.get(workingCopy) || 0;
139
+ }
140
+ discardBackup(workingCopy) {
141
+ this.cancelBackupOperation(workingCopy);
142
+ const workingCopyIdentifier = { resource: workingCopy.resource, typeId: workingCopy.typeId };
143
+ const cts = ( new CancellationTokenSource());
144
+ this.doDiscardBackup(workingCopyIdentifier, cts);
145
+ this.pendingBackupOperations.set(workingCopyIdentifier, {
146
+ cancel: () => {
147
+ this.logService.trace(`[backup tracker] clearing pending backup discard`, ( workingCopy.resource.toString()), workingCopy.typeId);
148
+ cts.cancel();
149
+ },
150
+ disposable: cts
151
+ });
152
+ }
153
+ async doDiscardBackup(workingCopyIdentifier, cts) {
154
+ this.logService.trace(`[backup tracker] discarding backup`, ( workingCopyIdentifier.resource.toString()), workingCopyIdentifier.typeId);
155
+ try {
156
+ await this.workingCopyBackupService.discardBackup(workingCopyIdentifier, cts.token);
157
+ }
158
+ catch (error) {
159
+ this.logService.error(error);
160
+ }
161
+ if (!cts.token.isCancellationRequested) {
162
+ this.doClearPendingBackupOperation(workingCopyIdentifier);
163
+ }
164
+ }
165
+ cancelBackupOperation(workingCopy) {
166
+ let workingCopyIdentifier = undefined;
167
+ for (const [identifier] of this.pendingBackupOperations) {
168
+ if (( identifier.resource.toString()) === ( workingCopy.resource.toString()) && identifier.typeId === workingCopy.typeId) {
169
+ workingCopyIdentifier = identifier;
170
+ break;
171
+ }
172
+ }
173
+ if (workingCopyIdentifier) {
174
+ this.doClearPendingBackupOperation(workingCopyIdentifier, { cancel: true });
175
+ }
176
+ }
177
+ doClearPendingBackupOperation(workingCopyIdentifier, options) {
178
+ const pendingBackupOperation = this.pendingBackupOperations.get(workingCopyIdentifier);
179
+ if (!pendingBackupOperation) {
180
+ return;
181
+ }
182
+ if (options?.cancel) {
183
+ pendingBackupOperation.cancel();
184
+ }
185
+ pendingBackupOperation.disposable.dispose();
186
+ this.pendingBackupOperations.delete(workingCopyIdentifier);
187
+ }
188
+ cancelBackupOperations() {
189
+ for (const [, operation] of this.pendingBackupOperations) {
190
+ operation.cancel();
191
+ operation.disposable.dispose();
192
+ }
193
+ this.pendingBackupOperations.clear();
194
+ }
195
+ suspendBackupOperations() {
196
+ this.suspended = true;
197
+ return { resume: () => this.suspended = false };
198
+ }
199
+ get isReady() { return this._isReady; }
200
+ async resolveBackupsToRestore() {
201
+ await this.lifecycleService.when(3 );
202
+ for (const backup of await this.workingCopyBackupService.getBackups()) {
203
+ this.unrestoredBackups.add(backup);
204
+ }
205
+ this._isReady = true;
206
+ }
207
+ async restoreBackups(handler) {
208
+ await this.whenReady;
209
+ const openedEditorsForBackups = ( new Set());
210
+ const nonOpenedEditorsForBackups = ( new Set());
211
+ const restoredBackups = ( new Set());
212
+ for (const unrestoredBackup of this.unrestoredBackups) {
213
+ const canHandleUnrestoredBackup = await handler.handles(unrestoredBackup);
214
+ if (!canHandleUnrestoredBackup) {
215
+ continue;
216
+ }
217
+ let hasOpenedEditorForBackup = false;
218
+ for (const { editor } of this.editorService.getEditors(0 )) {
219
+ const isUnrestoredBackupOpened = handler.isOpen(unrestoredBackup, editor);
220
+ if (isUnrestoredBackupOpened) {
221
+ openedEditorsForBackups.add(editor);
222
+ hasOpenedEditorForBackup = true;
223
+ }
224
+ }
225
+ if (!hasOpenedEditorForBackup) {
226
+ nonOpenedEditorsForBackups.add(await handler.createEditor(unrestoredBackup));
227
+ }
228
+ restoredBackups.add(unrestoredBackup);
229
+ }
230
+ if (nonOpenedEditorsForBackups.size > 0) {
231
+ await this.editorGroupService.activeGroup.openEditors(( [...nonOpenedEditorsForBackups].map(nonOpenedEditorForBackup => ({
232
+ editor: nonOpenedEditorForBackup,
233
+ options: {
234
+ pinned: true,
235
+ preserveFocus: true,
236
+ inactive: true
237
+ }
238
+ }))));
239
+ for (const nonOpenedEditorForBackup of nonOpenedEditorsForBackups) {
240
+ openedEditorsForBackups.add(nonOpenedEditorForBackup);
241
+ }
242
+ }
243
+ await Promises.settled(( [...openedEditorsForBackups].map(async (openedEditorForBackup) => {
244
+ if (this.editorService.isVisible(openedEditorForBackup)) {
245
+ return;
246
+ }
247
+ return openedEditorForBackup.resolve();
248
+ })));
249
+ for (const restoredBackup of restoredBackups) {
250
+ this.unrestoredBackups.delete(restoredBackup);
251
+ }
252
+ }
253
+ }
254
+
255
+ export { WorkingCopyBackupTracker };
@@ -0,0 +1,5 @@
1
+ import { IEditorOverrideServices } from 'vscode/vscode/vs/editor/standalone/browser/standaloneServices';
2
+
3
+ declare function getServiceOverride(): IEditorOverrideServices;
4
+
5
+ export { getServiceOverride as default };
package/workingCopy.js ADDED
@@ -0,0 +1,13 @@
1
+ import { SyncDescriptor } from 'monaco-editor/esm/vs/platform/instantiation/common/descriptors.js';
2
+ import { BrowserWorkingCopyBackupService } from './vscode/src/vs/workbench/services/workingCopy/browser/workingCopyBackupService.js';
3
+ import { IWorkingCopyBackupService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyBackup';
4
+ import getServiceOverride$1 from '@codingame/monaco-vscode-files-service-override';
5
+
6
+ function getServiceOverride() {
7
+ return {
8
+ ...getServiceOverride$1(),
9
+ [( IWorkingCopyBackupService.toString())]: new SyncDescriptor(BrowserWorkingCopyBackupService, [], false)
10
+ };
11
+ }
12
+
13
+ export { getServiceOverride as default };