@codingame/monaco-vscode-working-copy-service-override 1.85.2 → 1.85.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codingame/monaco-vscode-working-copy-service-override",
3
- "version": "1.85.2",
3
+ "version": "1.85.4",
4
4
  "keywords": [],
5
5
  "author": {
6
6
  "name": "CodinGame",
@@ -18,8 +18,8 @@
18
18
  "module": "index.js",
19
19
  "types": "index.d.ts",
20
20
  "dependencies": {
21
- "vscode": "npm:@codingame/monaco-vscode-api@1.85.2",
21
+ "vscode": "npm:@codingame/monaco-vscode-api@1.85.4",
22
22
  "monaco-editor": "0.45.0",
23
- "@codingame/monaco-vscode-files-service-override": "1.85.2"
23
+ "@codingame/monaco-vscode-files-service-override": "1.85.4"
24
24
  }
25
25
  }
@@ -0,0 +1,29 @@
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 { IRemoteAgentService } from 'vscode/vscode/vs/workbench/services/remote/common/remoteAgentService';
4
+ import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService';
5
+ import { IUriIdentityService } from 'monaco-editor/esm/vs/platform/uriIdentity/common/uriIdentity.js';
6
+ import { ILabelService } from 'monaco-editor/esm/vs/platform/label/common/label.js';
7
+ import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
8
+ import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
9
+ import { WorkingCopyHistoryService } from '../common/workingCopyHistoryService.js';
10
+
11
+ let BrowserWorkingCopyHistoryService = class BrowserWorkingCopyHistoryService extends WorkingCopyHistoryService {
12
+ constructor(fileService, remoteAgentService, environmentService, uriIdentityService, labelService, logService, configurationService) {
13
+ super(fileService, remoteAgentService, environmentService, uriIdentityService, labelService, logService, configurationService);
14
+ }
15
+ getModelOptions() {
16
+ return { flushOnChange: true };
17
+ }
18
+ };
19
+ BrowserWorkingCopyHistoryService = ( __decorate([
20
+ ( __param(0, IFileService)),
21
+ ( __param(1, IRemoteAgentService)),
22
+ ( __param(2, IWorkbenchEnvironmentService)),
23
+ ( __param(3, IUriIdentityService)),
24
+ ( __param(4, ILabelService)),
25
+ ( __param(5, ILogService)),
26
+ ( __param(6, IConfigurationService))
27
+ ], BrowserWorkingCopyHistoryService));
28
+
29
+ export { BrowserWorkingCopyHistoryService };
@@ -0,0 +1,618 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
3
+ import { Emitter, Event } from 'monaco-editor/esm/vs/base/common/event.js';
4
+ import { assertIsDefined } from 'monaco-editor/esm/vs/base/common/types.js';
5
+ import { Registry } from 'monaco-editor/esm/vs/platform/registry/common/platform.js';
6
+ import { Extensions } from 'vscode/vscode/vs/workbench/common/contributions';
7
+ import { ILifecycleService } from 'vscode/vscode/vs/workbench/services/lifecycle/common/lifecycle';
8
+ import { WorkingCopyHistoryTracker } from './workingCopyHistoryTracker.js';
9
+ import { Disposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
10
+ import { MAX_PARALLEL_HISTORY_IO_OPS } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyHistory';
11
+ import { FileOperationError, IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
12
+ import { IRemoteAgentService } from 'vscode/vscode/vs/workbench/services/remote/common/remoteAgentService';
13
+ import { URI } from 'monaco-editor/esm/vs/base/common/uri.js';
14
+ import { Limiter, DeferredPromise, RunOnceScheduler } from 'monaco-editor/esm/vs/base/common/async.js';
15
+ import { extname, joinPath, isEqual, dirname } from 'monaco-editor/esm/vs/base/common/resources.js';
16
+ import { IWorkbenchEnvironmentService } from 'vscode/vscode/vs/workbench/services/environment/common/environmentService';
17
+ import { hash } from 'monaco-editor/esm/vs/base/common/hash.js';
18
+ import { randomPath, indexOfPath } from 'monaco-editor/esm/vs/base/common/extpath.js';
19
+ import { CancellationToken, CancellationTokenSource } from 'monaco-editor/esm/vs/base/common/cancellation.js';
20
+ import { ResourceMap } from 'monaco-editor/esm/vs/base/common/map.js';
21
+ import { IUriIdentityService } from 'monaco-editor/esm/vs/platform/uriIdentity/common/uriIdentity.js';
22
+ import { ILabelService } from 'monaco-editor/esm/vs/platform/label/common/label.js';
23
+ import { VSBuffer } from 'monaco-editor/esm/vs/base/common/buffer.js';
24
+ import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
25
+ import { SaveSourceRegistry } from 'vscode/vscode/vs/workbench/common/editor';
26
+ import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
27
+ import { lastOrDefault } from 'monaco-editor/esm/vs/base/common/arrays.js';
28
+ import { escapeRegExpCharacters } from 'monaco-editor/esm/vs/base/common/strings.js';
29
+
30
+ var WorkingCopyHistoryService_1, NativeWorkingCopyHistoryService_1;
31
+ class WorkingCopyHistoryModel {
32
+ static { this.ENTRIES_FILE = 'entries.json'; }
33
+ static { this.FILE_SAVED_SOURCE = SaveSourceRegistry.registerSource('default.source', ( localizeWithPath(
34
+ 'vs/workbench/services/workingCopy/common/workingCopyHistoryService',
35
+ 'default.source',
36
+ "File Saved"
37
+ ))); }
38
+ static { this.SETTINGS = {
39
+ MAX_ENTRIES: 'workbench.localHistory.maxFileEntries',
40
+ MERGE_PERIOD: 'workbench.localHistory.mergeWindow'
41
+ }; }
42
+ constructor(workingCopyResource, historyHome, entryAddedEmitter, entryChangedEmitter, entryReplacedEmitter, entryRemovedEmitter, options, fileService, labelService, logService, configurationService) {
43
+ this.historyHome = historyHome;
44
+ this.entryAddedEmitter = entryAddedEmitter;
45
+ this.entryChangedEmitter = entryChangedEmitter;
46
+ this.entryReplacedEmitter = entryReplacedEmitter;
47
+ this.entryRemovedEmitter = entryRemovedEmitter;
48
+ this.options = options;
49
+ this.fileService = fileService;
50
+ this.labelService = labelService;
51
+ this.logService = logService;
52
+ this.configurationService = configurationService;
53
+ this.entries = [];
54
+ this.whenResolved = undefined;
55
+ this.workingCopyResource = undefined;
56
+ this.workingCopyName = undefined;
57
+ this.historyEntriesFolder = undefined;
58
+ this.historyEntriesListingFile = undefined;
59
+ this.historyEntriesNameMatcher = undefined;
60
+ this.versionId = 0;
61
+ this.storedVersionId = this.versionId;
62
+ this.storeLimiter = ( new Limiter(1));
63
+ this.setWorkingCopy(workingCopyResource);
64
+ }
65
+ setWorkingCopy(workingCopyResource) {
66
+ this.workingCopyResource = workingCopyResource;
67
+ this.workingCopyName = this.labelService.getUriBasenameLabel(workingCopyResource);
68
+ this.historyEntriesNameMatcher = ( new RegExp(`[A-Za-z0-9]{4}${escapeRegExpCharacters(extname(workingCopyResource))}`));
69
+ this.historyEntriesFolder = this.toHistoryEntriesFolder(this.historyHome, workingCopyResource);
70
+ this.historyEntriesListingFile = joinPath(this.historyEntriesFolder, WorkingCopyHistoryModel.ENTRIES_FILE);
71
+ this.entries = [];
72
+ this.whenResolved = undefined;
73
+ }
74
+ toHistoryEntriesFolder(historyHome, workingCopyResource) {
75
+ return joinPath(historyHome, ( hash(( workingCopyResource.toString())).toString(16)));
76
+ }
77
+ async addEntry(source = WorkingCopyHistoryModel.FILE_SAVED_SOURCE, timestamp = Date.now(), token) {
78
+ let entryToReplace = undefined;
79
+ const lastEntry = lastOrDefault(this.entries);
80
+ if (lastEntry && lastEntry.source === source) {
81
+ const configuredReplaceInterval = this.configurationService.getValue(WorkingCopyHistoryModel.SETTINGS.MERGE_PERIOD, { resource: this.workingCopyResource });
82
+ if (timestamp - lastEntry.timestamp <= ((configuredReplaceInterval * 1000) )) {
83
+ entryToReplace = lastEntry;
84
+ }
85
+ }
86
+ let entry;
87
+ if (entryToReplace) {
88
+ entry = await this.doReplaceEntry(entryToReplace, timestamp, token);
89
+ }
90
+ else {
91
+ entry = await this.doAddEntry(source, timestamp, token);
92
+ }
93
+ if (this.options.flushOnChange && !token.isCancellationRequested) {
94
+ await this.store(token);
95
+ }
96
+ return entry;
97
+ }
98
+ async doAddEntry(source, timestamp, token) {
99
+ const workingCopyResource = assertIsDefined(this.workingCopyResource);
100
+ const workingCopyName = assertIsDefined(this.workingCopyName);
101
+ const historyEntriesFolder = assertIsDefined(this.historyEntriesFolder);
102
+ const id = `${randomPath(undefined, undefined, 4)}${extname(workingCopyResource)}`;
103
+ const location = joinPath(historyEntriesFolder, id);
104
+ await this.fileService.cloneFile(workingCopyResource, location);
105
+ const entry = {
106
+ id,
107
+ workingCopy: { resource: workingCopyResource, name: workingCopyName },
108
+ location,
109
+ timestamp,
110
+ source
111
+ };
112
+ this.entries.push(entry);
113
+ this.versionId++;
114
+ this.entryAddedEmitter.fire({ entry });
115
+ return entry;
116
+ }
117
+ async doReplaceEntry(entry, timestamp, token) {
118
+ const workingCopyResource = assertIsDefined(this.workingCopyResource);
119
+ await this.fileService.cloneFile(workingCopyResource, entry.location);
120
+ entry.timestamp = timestamp;
121
+ this.versionId++;
122
+ this.entryReplacedEmitter.fire({ entry });
123
+ return entry;
124
+ }
125
+ async removeEntry(entry, token) {
126
+ await this.resolveEntriesOnce();
127
+ if (token.isCancellationRequested) {
128
+ return false;
129
+ }
130
+ const index = this.entries.indexOf(entry);
131
+ if (index === -1) {
132
+ return false;
133
+ }
134
+ await this.deleteEntry(entry);
135
+ this.entries.splice(index, 1);
136
+ this.versionId++;
137
+ this.entryRemovedEmitter.fire({ entry });
138
+ if (this.options.flushOnChange && !token.isCancellationRequested) {
139
+ await this.store(token);
140
+ }
141
+ return true;
142
+ }
143
+ async updateEntry(entry, properties, token) {
144
+ await this.resolveEntriesOnce();
145
+ if (token.isCancellationRequested) {
146
+ return;
147
+ }
148
+ const index = this.entries.indexOf(entry);
149
+ if (index === -1) {
150
+ return;
151
+ }
152
+ entry.source = properties.source;
153
+ this.versionId++;
154
+ this.entryChangedEmitter.fire({ entry });
155
+ if (this.options.flushOnChange && !token.isCancellationRequested) {
156
+ await this.store(token);
157
+ }
158
+ }
159
+ async getEntries() {
160
+ await this.resolveEntriesOnce();
161
+ const configuredMaxEntries = this.configurationService.getValue(WorkingCopyHistoryModel.SETTINGS.MAX_ENTRIES, { resource: this.workingCopyResource });
162
+ if (this.entries.length > configuredMaxEntries) {
163
+ return this.entries.slice(this.entries.length - configuredMaxEntries);
164
+ }
165
+ return this.entries;
166
+ }
167
+ async hasEntries(skipResolve) {
168
+ if (!skipResolve) {
169
+ await this.resolveEntriesOnce();
170
+ }
171
+ return this.entries.length > 0;
172
+ }
173
+ resolveEntriesOnce() {
174
+ if (!this.whenResolved) {
175
+ this.whenResolved = this.doResolveEntries();
176
+ }
177
+ return this.whenResolved;
178
+ }
179
+ async doResolveEntries() {
180
+ const entries = await this.resolveEntriesFromDisk();
181
+ for (const entry of this.entries) {
182
+ entries.set(entry.id, entry);
183
+ }
184
+ this.entries = Array.from(( entries.values())).sort((entryA, entryB) => entryA.timestamp - entryB.timestamp);
185
+ }
186
+ async resolveEntriesFromDisk() {
187
+ const workingCopyResource = assertIsDefined(this.workingCopyResource);
188
+ const workingCopyName = assertIsDefined(this.workingCopyName);
189
+ const [entryListing, entryStats] = await Promise.all([
190
+ this.readEntriesFile(),
191
+ this.readEntriesFolder()
192
+ ]);
193
+ const entries = ( new Map());
194
+ if (entryStats) {
195
+ for (const entryStat of entryStats) {
196
+ entries.set(entryStat.name, {
197
+ id: entryStat.name,
198
+ workingCopy: { resource: workingCopyResource, name: workingCopyName },
199
+ location: entryStat.resource,
200
+ timestamp: entryStat.mtime,
201
+ source: WorkingCopyHistoryModel.FILE_SAVED_SOURCE
202
+ });
203
+ }
204
+ }
205
+ if (entryListing) {
206
+ for (const entry of entryListing.entries) {
207
+ const existingEntry = entries.get(entry.id);
208
+ if (existingEntry) {
209
+ entries.set(entry.id, {
210
+ ...existingEntry,
211
+ timestamp: entry.timestamp,
212
+ source: entry.source ?? existingEntry.source
213
+ });
214
+ }
215
+ }
216
+ }
217
+ return entries;
218
+ }
219
+ async moveEntries(targetWorkingCopyResource, source, token) {
220
+ await this.store(token);
221
+ if (token.isCancellationRequested) {
222
+ return undefined;
223
+ }
224
+ const sourceHistoryEntriesFolder = assertIsDefined(this.historyEntriesFolder);
225
+ const targetHistoryFolder = this.toHistoryEntriesFolder(this.historyHome, targetWorkingCopyResource);
226
+ try {
227
+ await this.fileService.move(sourceHistoryEntriesFolder, targetHistoryFolder, true);
228
+ }
229
+ catch (error) {
230
+ if (!((error instanceof FileOperationError && error.fileOperationResult === 1) )) {
231
+ this.traceError(error);
232
+ }
233
+ }
234
+ this.setWorkingCopy(targetWorkingCopyResource);
235
+ await this.addEntry(source, undefined, token);
236
+ await this.store(token);
237
+ }
238
+ async store(token) {
239
+ if (!this.shouldStore()) {
240
+ return;
241
+ }
242
+ await this.storeLimiter.queue(async () => {
243
+ if (token.isCancellationRequested || !this.shouldStore()) {
244
+ return;
245
+ }
246
+ return this.doStore(token);
247
+ });
248
+ }
249
+ shouldStore() {
250
+ return this.storedVersionId !== this.versionId;
251
+ }
252
+ async doStore(token) {
253
+ const historyEntriesFolder = assertIsDefined(this.historyEntriesFolder);
254
+ await this.resolveEntriesOnce();
255
+ if (token.isCancellationRequested) {
256
+ return undefined;
257
+ }
258
+ await this.cleanUpEntries();
259
+ const storedVersion = this.versionId;
260
+ if (this.entries.length === 0) {
261
+ try {
262
+ await this.fileService.del(historyEntriesFolder, { recursive: true });
263
+ }
264
+ catch (error) {
265
+ this.traceError(error);
266
+ }
267
+ }
268
+ else {
269
+ await this.writeEntriesFile();
270
+ }
271
+ this.storedVersionId = storedVersion;
272
+ }
273
+ async cleanUpEntries() {
274
+ const configuredMaxEntries = this.configurationService.getValue(WorkingCopyHistoryModel.SETTINGS.MAX_ENTRIES, { resource: this.workingCopyResource });
275
+ if (this.entries.length <= configuredMaxEntries) {
276
+ return;
277
+ }
278
+ const entriesToDelete = this.entries.slice(0, this.entries.length - configuredMaxEntries);
279
+ const entriesToKeep = this.entries.slice(this.entries.length - configuredMaxEntries);
280
+ for (const entryToDelete of entriesToDelete) {
281
+ await this.deleteEntry(entryToDelete);
282
+ }
283
+ this.entries = entriesToKeep;
284
+ for (const entry of entriesToDelete) {
285
+ this.entryRemovedEmitter.fire({ entry });
286
+ }
287
+ }
288
+ async deleteEntry(entry) {
289
+ try {
290
+ await this.fileService.del(entry.location);
291
+ }
292
+ catch (error) {
293
+ this.traceError(error);
294
+ }
295
+ }
296
+ async writeEntriesFile() {
297
+ const workingCopyResource = assertIsDefined(this.workingCopyResource);
298
+ const historyEntriesListingFile = assertIsDefined(this.historyEntriesListingFile);
299
+ const serializedModel = {
300
+ version: 1,
301
+ resource: ( workingCopyResource.toString()),
302
+ entries: ( this.entries.map(entry => {
303
+ return {
304
+ id: entry.id,
305
+ source: entry.source !== WorkingCopyHistoryModel.FILE_SAVED_SOURCE ? entry.source : undefined,
306
+ timestamp: entry.timestamp
307
+ };
308
+ }))
309
+ };
310
+ await this.fileService.writeFile(historyEntriesListingFile, VSBuffer.fromString(JSON.stringify(serializedModel)));
311
+ }
312
+ async readEntriesFile() {
313
+ const historyEntriesListingFile = assertIsDefined(this.historyEntriesListingFile);
314
+ let serializedModel = undefined;
315
+ try {
316
+ serializedModel = JSON.parse(( (await this.fileService.readFile(historyEntriesListingFile)).value.toString()));
317
+ }
318
+ catch (error) {
319
+ if (!((error instanceof FileOperationError && error.fileOperationResult === 1) )) {
320
+ this.traceError(error);
321
+ }
322
+ }
323
+ return serializedModel;
324
+ }
325
+ async readEntriesFolder() {
326
+ const historyEntriesFolder = assertIsDefined(this.historyEntriesFolder);
327
+ const historyEntriesNameMatcher = assertIsDefined(this.historyEntriesNameMatcher);
328
+ let rawEntries = undefined;
329
+ try {
330
+ rawEntries = (await this.fileService.resolve(historyEntriesFolder, { resolveMetadata: true })).children;
331
+ }
332
+ catch (error) {
333
+ if (!((error instanceof FileOperationError && error.fileOperationResult === 1) )) {
334
+ this.traceError(error);
335
+ }
336
+ }
337
+ if (!rawEntries) {
338
+ return undefined;
339
+ }
340
+ return rawEntries.filter(entry => !isEqual(entry.resource, this.historyEntriesListingFile) &&
341
+ historyEntriesNameMatcher.test(entry.name)
342
+ );
343
+ }
344
+ traceError(error) {
345
+ this.logService.trace('[Working Copy History Service]', error);
346
+ }
347
+ }
348
+ let WorkingCopyHistoryService = class WorkingCopyHistoryService extends Disposable {
349
+ static { WorkingCopyHistoryService_1 = this; }
350
+ static { this.FILE_MOVED_SOURCE = SaveSourceRegistry.registerSource('moved.source', ( localizeWithPath(
351
+ 'vs/workbench/services/workingCopy/common/workingCopyHistoryService',
352
+ 'moved.source',
353
+ "File Moved"
354
+ ))); }
355
+ static { this.FILE_RENAMED_SOURCE = SaveSourceRegistry.registerSource('renamed.source', ( localizeWithPath(
356
+ 'vs/workbench/services/workingCopy/common/workingCopyHistoryService',
357
+ 'renamed.source',
358
+ "File Renamed"
359
+ ))); }
360
+ constructor(fileService, remoteAgentService, environmentService, uriIdentityService, labelService, logService, configurationService) {
361
+ super();
362
+ this.fileService = fileService;
363
+ this.remoteAgentService = remoteAgentService;
364
+ this.environmentService = environmentService;
365
+ this.uriIdentityService = uriIdentityService;
366
+ this.labelService = labelService;
367
+ this.logService = logService;
368
+ this.configurationService = configurationService;
369
+ this._onDidAddEntry = this._register(( new Emitter()));
370
+ this.onDidAddEntry = this._onDidAddEntry.event;
371
+ this._onDidChangeEntry = this._register(( new Emitter()));
372
+ this.onDidChangeEntry = this._onDidChangeEntry.event;
373
+ this._onDidReplaceEntry = this._register(( new Emitter()));
374
+ this.onDidReplaceEntry = this._onDidReplaceEntry.event;
375
+ this._onDidMoveEntries = this._register(( new Emitter()));
376
+ this.onDidMoveEntries = this._onDidMoveEntries.event;
377
+ this._onDidRemoveEntry = this._register(( new Emitter()));
378
+ this.onDidRemoveEntry = this._onDidRemoveEntry.event;
379
+ this._onDidRemoveEntries = this._register(( new Emitter()));
380
+ this.onDidRemoveEntries = this._onDidRemoveEntries.event;
381
+ this.localHistoryHome = ( new DeferredPromise());
382
+ this.models = ( new ResourceMap(resource => this.uriIdentityService.extUri.getComparisonKey(resource)));
383
+ this.resolveLocalHistoryHome();
384
+ }
385
+ async resolveLocalHistoryHome() {
386
+ let historyHome = undefined;
387
+ try {
388
+ const remoteEnv = await this.remoteAgentService.getEnvironment();
389
+ if (remoteEnv) {
390
+ historyHome = remoteEnv.localHistoryHome;
391
+ }
392
+ }
393
+ catch (error) {
394
+ this.logService.trace(error);
395
+ }
396
+ if (!historyHome) {
397
+ historyHome = this.environmentService.localHistoryHome;
398
+ }
399
+ this.localHistoryHome.complete(historyHome);
400
+ }
401
+ async moveEntries(source, target) {
402
+ const limiter = ( new Limiter(MAX_PARALLEL_HISTORY_IO_OPS));
403
+ const promises = [];
404
+ for (const [resource, model] of this.models) {
405
+ if (!this.uriIdentityService.extUri.isEqualOrParent(resource, source)) {
406
+ continue;
407
+ }
408
+ let targetResource;
409
+ if (this.uriIdentityService.extUri.isEqual(source, resource)) {
410
+ targetResource = target;
411
+ }
412
+ else {
413
+ const index = indexOfPath(resource.path, source.path);
414
+ targetResource = joinPath(target, resource.path.substr(index + source.path.length + 1));
415
+ }
416
+ let saveSource;
417
+ if (this.uriIdentityService.extUri.isEqual(dirname(resource), dirname(targetResource))) {
418
+ saveSource = WorkingCopyHistoryService_1.FILE_RENAMED_SOURCE;
419
+ }
420
+ else {
421
+ saveSource = WorkingCopyHistoryService_1.FILE_MOVED_SOURCE;
422
+ }
423
+ promises.push(limiter.queue(() => this.doMoveEntries(model, saveSource, resource, targetResource)));
424
+ }
425
+ if (!promises.length) {
426
+ return [];
427
+ }
428
+ const resources = await Promise.all(promises);
429
+ this._onDidMoveEntries.fire();
430
+ return resources;
431
+ }
432
+ async doMoveEntries(model, source, sourceWorkingCopyResource, targetWorkingCopyResource) {
433
+ await model.moveEntries(targetWorkingCopyResource, source, CancellationToken.None);
434
+ this.models.delete(sourceWorkingCopyResource);
435
+ this.models.set(targetWorkingCopyResource, model);
436
+ return targetWorkingCopyResource;
437
+ }
438
+ async addEntry({ resource, source, timestamp }, token) {
439
+ if (!this.fileService.hasProvider(resource)) {
440
+ return undefined;
441
+ }
442
+ const model = await this.getModel(resource);
443
+ if (token.isCancellationRequested) {
444
+ return undefined;
445
+ }
446
+ return model.addEntry(source, timestamp, token);
447
+ }
448
+ async updateEntry(entry, properties, token) {
449
+ const model = await this.getModel(entry.workingCopy.resource);
450
+ if (token.isCancellationRequested) {
451
+ return;
452
+ }
453
+ return model.updateEntry(entry, properties, token);
454
+ }
455
+ async removeEntry(entry, token) {
456
+ const model = await this.getModel(entry.workingCopy.resource);
457
+ if (token.isCancellationRequested) {
458
+ return false;
459
+ }
460
+ return model.removeEntry(entry, token);
461
+ }
462
+ async removeAll(token) {
463
+ const historyHome = await this.localHistoryHome.p;
464
+ if (token.isCancellationRequested) {
465
+ return;
466
+ }
467
+ this.models.clear();
468
+ await this.fileService.del(historyHome, { recursive: true });
469
+ this._onDidRemoveEntries.fire();
470
+ }
471
+ async getEntries(resource, token) {
472
+ const model = await this.getModel(resource);
473
+ if (token.isCancellationRequested) {
474
+ return [];
475
+ }
476
+ const entries = await model.getEntries();
477
+ return entries ?? [];
478
+ }
479
+ async getAll(token) {
480
+ const historyHome = await this.localHistoryHome.p;
481
+ if (token.isCancellationRequested) {
482
+ return [];
483
+ }
484
+ const all = ( new ResourceMap());
485
+ for (const [resource, model] of this.models) {
486
+ const hasInMemoryEntries = await model.hasEntries(true );
487
+ if (hasInMemoryEntries) {
488
+ all.set(resource, true);
489
+ }
490
+ }
491
+ try {
492
+ const resolvedHistoryHome = await this.fileService.resolve(historyHome);
493
+ if (resolvedHistoryHome.children) {
494
+ const limiter = ( new Limiter(MAX_PARALLEL_HISTORY_IO_OPS));
495
+ const promises = [];
496
+ for (const child of resolvedHistoryHome.children) {
497
+ promises.push(limiter.queue(async () => {
498
+ if (token.isCancellationRequested) {
499
+ return;
500
+ }
501
+ try {
502
+ const serializedModel = JSON.parse(( (await this.fileService.readFile(joinPath(child.resource, WorkingCopyHistoryModel.ENTRIES_FILE))).value.toString()));
503
+ if (serializedModel.entries.length > 0) {
504
+ all.set(( URI.parse(serializedModel.resource)), true);
505
+ }
506
+ }
507
+ catch (error) {
508
+ }
509
+ }));
510
+ }
511
+ await Promise.all(promises);
512
+ }
513
+ }
514
+ catch (error) {
515
+ }
516
+ return Array.from(( all.keys()));
517
+ }
518
+ async getModel(resource) {
519
+ const historyHome = await this.localHistoryHome.p;
520
+ let model = this.models.get(resource);
521
+ if (!model) {
522
+ model = ( new WorkingCopyHistoryModel(
523
+ resource,
524
+ historyHome,
525
+ this._onDidAddEntry,
526
+ this._onDidChangeEntry,
527
+ this._onDidReplaceEntry,
528
+ this._onDidRemoveEntry,
529
+ this.getModelOptions(),
530
+ this.fileService,
531
+ this.labelService,
532
+ this.logService,
533
+ this.configurationService
534
+ ));
535
+ this.models.set(resource, model);
536
+ }
537
+ return model;
538
+ }
539
+ };
540
+ WorkingCopyHistoryService = WorkingCopyHistoryService_1 = ( __decorate([
541
+ ( __param(0, IFileService)),
542
+ ( __param(1, IRemoteAgentService)),
543
+ ( __param(2, IWorkbenchEnvironmentService)),
544
+ ( __param(3, IUriIdentityService)),
545
+ ( __param(4, ILabelService)),
546
+ ( __param(5, ILogService)),
547
+ ( __param(6, IConfigurationService))
548
+ ], WorkingCopyHistoryService));
549
+ let NativeWorkingCopyHistoryService = class NativeWorkingCopyHistoryService extends WorkingCopyHistoryService {
550
+ static { NativeWorkingCopyHistoryService_1 = this; }
551
+ static { this.STORE_ALL_INTERVAL = 5 * 60 * 1000; }
552
+ constructor(fileService, remoteAgentService, environmentService, uriIdentityService, labelService, lifecycleService, logService, configurationService) {
553
+ super(fileService, remoteAgentService, environmentService, uriIdentityService, labelService, logService, configurationService);
554
+ this.lifecycleService = lifecycleService;
555
+ this.isRemotelyStored = typeof this.environmentService.remoteAuthority === 'string';
556
+ this.storeAllCts = this._register(( new CancellationTokenSource()));
557
+ this.storeAllScheduler = this._register(( new RunOnceScheduler(
558
+ () => this.storeAll(this.storeAllCts.token),
559
+ NativeWorkingCopyHistoryService_1.STORE_ALL_INTERVAL
560
+ )));
561
+ this.registerListeners();
562
+ }
563
+ registerListeners() {
564
+ if (!this.isRemotelyStored) {
565
+ this._register(this.lifecycleService.onWillShutdown(e => this.onWillShutdown(e)));
566
+ this._register(Event.any(this.onDidAddEntry, this.onDidChangeEntry, this.onDidReplaceEntry, this.onDidRemoveEntry)(() => this.onDidChangeModels()));
567
+ }
568
+ }
569
+ getModelOptions() {
570
+ return { flushOnChange: this.isRemotelyStored };
571
+ }
572
+ onWillShutdown(e) {
573
+ this.storeAllScheduler.dispose();
574
+ this.storeAllCts.dispose(true);
575
+ e.join(this.storeAll(e.token), { id: 'join.workingCopyHistory', label: ( localizeWithPath(
576
+ 'vs/workbench/services/workingCopy/common/workingCopyHistoryService',
577
+ 'join.workingCopyHistory',
578
+ "Saving local history"
579
+ )) });
580
+ }
581
+ onDidChangeModels() {
582
+ if (!this.storeAllScheduler.isScheduled()) {
583
+ this.storeAllScheduler.schedule();
584
+ }
585
+ }
586
+ async storeAll(token) {
587
+ const limiter = ( new Limiter(MAX_PARALLEL_HISTORY_IO_OPS));
588
+ const promises = [];
589
+ const models = Array.from(( this.models.values()));
590
+ for (const model of models) {
591
+ promises.push(limiter.queue(async () => {
592
+ if (token.isCancellationRequested) {
593
+ return;
594
+ }
595
+ try {
596
+ await model.store(token);
597
+ }
598
+ catch (error) {
599
+ this.logService.trace(error);
600
+ }
601
+ }));
602
+ }
603
+ await Promise.all(promises);
604
+ }
605
+ };
606
+ NativeWorkingCopyHistoryService = NativeWorkingCopyHistoryService_1 = ( __decorate([
607
+ ( __param(0, IFileService)),
608
+ ( __param(1, IRemoteAgentService)),
609
+ ( __param(2, IWorkbenchEnvironmentService)),
610
+ ( __param(3, IUriIdentityService)),
611
+ ( __param(4, ILabelService)),
612
+ ( __param(5, ILifecycleService)),
613
+ ( __param(6, ILogService)),
614
+ ( __param(7, IConfigurationService))
615
+ ], NativeWorkingCopyHistoryService));
616
+ ( Registry.as(Extensions.Workbench)).registerWorkbenchContribution(WorkingCopyHistoryTracker, 3 );
617
+
618
+ export { NativeWorkingCopyHistoryService, WorkingCopyHistoryModel, WorkingCopyHistoryService };
@@ -0,0 +1,164 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import { localizeWithPath } from 'monaco-editor/esm/vs/nls.js';
3
+ import { Limiter, GlobalIdleValue } from 'monaco-editor/esm/vs/base/common/async.js';
4
+ import { CancellationTokenSource } from 'monaco-editor/esm/vs/base/common/cancellation.js';
5
+ import { Disposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
6
+ import { ResourceMap } from 'monaco-editor/esm/vs/base/common/map.js';
7
+ import { IConfigurationService } from 'monaco-editor/esm/vs/platform/configuration/common/configuration.js';
8
+ import { IUndoRedoService } from 'monaco-editor/esm/vs/platform/undoRedo/common/undoRedo.js';
9
+ import { IUriIdentityService } from 'monaco-editor/esm/vs/platform/uriIdentity/common/uriIdentity.js';
10
+ import { SaveSourceRegistry } from 'vscode/vscode/vs/workbench/common/editor';
11
+ import { IPathService } from 'vscode/vscode/vs/workbench/services/path/common/pathService';
12
+ import { isStoredFileWorkingCopySaveEvent } from 'vscode/vscode/vs/workbench/services/workingCopy/common/storedFileWorkingCopy';
13
+ import { MAX_PARALLEL_HISTORY_IO_OPS, IWorkingCopyHistoryService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyHistory';
14
+ import { IWorkingCopyService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyService';
15
+ import { Schemas } from 'monaco-editor/esm/vs/base/common/network.js';
16
+ import { ResourceGlobMatcher } from 'vscode/vscode/vs/workbench/common/resources';
17
+ import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
18
+ import { IFileService } from 'monaco-editor/esm/vs/platform/files/common/files.js';
19
+
20
+ var WorkingCopyHistoryTracker_1;
21
+ let WorkingCopyHistoryTracker = class WorkingCopyHistoryTracker extends Disposable {
22
+ static { WorkingCopyHistoryTracker_1 = this; }
23
+ static { this.SETTINGS = {
24
+ ENABLED: 'workbench.localHistory.enabled',
25
+ SIZE_LIMIT: 'workbench.localHistory.maxFileSize',
26
+ EXCLUDES: 'workbench.localHistory.exclude'
27
+ }; }
28
+ static { this.UNDO_REDO_SAVE_SOURCE = SaveSourceRegistry.registerSource('undoRedo.source', ( localizeWithPath(
29
+ 'vs/workbench/services/workingCopy/common/workingCopyHistoryTracker',
30
+ 'undoRedo.source',
31
+ "Undo / Redo"
32
+ ))); }
33
+ constructor(workingCopyService, workingCopyHistoryService, uriIdentityService, pathService, configurationService, undoRedoService, contextService, fileService) {
34
+ super();
35
+ this.workingCopyService = workingCopyService;
36
+ this.workingCopyHistoryService = workingCopyHistoryService;
37
+ this.uriIdentityService = uriIdentityService;
38
+ this.pathService = pathService;
39
+ this.configurationService = configurationService;
40
+ this.undoRedoService = undoRedoService;
41
+ this.contextService = contextService;
42
+ this.fileService = fileService;
43
+ this.limiter = this._register(( new Limiter(MAX_PARALLEL_HISTORY_IO_OPS)));
44
+ this.resourceExcludeMatcher = this._register(( new GlobalIdleValue(() => {
45
+ const matcher = this._register(( new ResourceGlobMatcher(
46
+ root => this.configurationService.getValue(WorkingCopyHistoryTracker_1.SETTINGS.EXCLUDES, { resource: root }),
47
+ event => event.affectsConfiguration(WorkingCopyHistoryTracker_1.SETTINGS.EXCLUDES),
48
+ this.contextService,
49
+ this.configurationService
50
+ )));
51
+ return matcher;
52
+ })));
53
+ this.pendingAddHistoryEntryOperations = ( new ResourceMap(resource => this.uriIdentityService.extUri.getComparisonKey(resource)));
54
+ this.workingCopyContentVersion = ( new ResourceMap(resource => this.uriIdentityService.extUri.getComparisonKey(resource)));
55
+ this.historyEntryContentVersion = ( new ResourceMap(resource => this.uriIdentityService.extUri.getComparisonKey(resource)));
56
+ this.registerListeners();
57
+ }
58
+ registerListeners() {
59
+ this._register(this.fileService.onDidRunOperation(e => this.onDidRunFileOperation(e)));
60
+ this._register(this.workingCopyService.onDidChangeContent(workingCopy => this.onDidChangeContent(workingCopy)));
61
+ this._register(this.workingCopyService.onDidSave(e => this.onDidSave(e)));
62
+ }
63
+ async onDidRunFileOperation(e) {
64
+ if (!this.shouldTrackHistoryFromFileOperationEvent(e)) {
65
+ return;
66
+ }
67
+ const source = e.resource;
68
+ const target = e.target.resource;
69
+ const resources = await this.workingCopyHistoryService.moveEntries(source, target);
70
+ for (const resource of resources) {
71
+ const contentVersion = this.getContentVersion(resource);
72
+ this.historyEntryContentVersion.set(resource, contentVersion);
73
+ }
74
+ }
75
+ onDidChangeContent(workingCopy) {
76
+ const contentVersionId = this.getContentVersion(workingCopy.resource);
77
+ this.workingCopyContentVersion.set(workingCopy.resource, contentVersionId + 1);
78
+ }
79
+ getContentVersion(resource) {
80
+ return this.workingCopyContentVersion.get(resource) || 0;
81
+ }
82
+ onDidSave(e) {
83
+ if (!this.shouldTrackHistoryFromSaveEvent(e)) {
84
+ return;
85
+ }
86
+ const contentVersion = this.getContentVersion(e.workingCopy.resource);
87
+ if (this.historyEntryContentVersion.get(e.workingCopy.resource) === contentVersion) {
88
+ return;
89
+ }
90
+ this.pendingAddHistoryEntryOperations.get(e.workingCopy.resource)?.dispose(true);
91
+ const cts = ( new CancellationTokenSource());
92
+ this.pendingAddHistoryEntryOperations.set(e.workingCopy.resource, cts);
93
+ this.limiter.queue(async () => {
94
+ if (cts.token.isCancellationRequested) {
95
+ return;
96
+ }
97
+ const contentVersion = this.getContentVersion(e.workingCopy.resource);
98
+ let source = e.source;
99
+ if (!e.source) {
100
+ source = this.resolveSourceFromUndoRedo(e);
101
+ }
102
+ await this.workingCopyHistoryService.addEntry({ resource: e.workingCopy.resource, source, timestamp: e.stat.mtime }, cts.token);
103
+ this.historyEntryContentVersion.set(e.workingCopy.resource, contentVersion);
104
+ if (cts.token.isCancellationRequested) {
105
+ return;
106
+ }
107
+ this.pendingAddHistoryEntryOperations.delete(e.workingCopy.resource);
108
+ });
109
+ }
110
+ resolveSourceFromUndoRedo(e) {
111
+ const lastStackElement = this.undoRedoService.getLastElement(e.workingCopy.resource);
112
+ if (lastStackElement) {
113
+ if (lastStackElement.code === 'undoredo.textBufferEdit') {
114
+ return undefined;
115
+ }
116
+ return lastStackElement.label;
117
+ }
118
+ const allStackElements = this.undoRedoService.getElements(e.workingCopy.resource);
119
+ if (allStackElements.future.length > 0 || allStackElements.past.length > 0) {
120
+ return WorkingCopyHistoryTracker_1.UNDO_REDO_SAVE_SOURCE;
121
+ }
122
+ return undefined;
123
+ }
124
+ shouldTrackHistoryFromSaveEvent(e) {
125
+ if (!isStoredFileWorkingCopySaveEvent(e)) {
126
+ return false;
127
+ }
128
+ return this.shouldTrackHistory(e.workingCopy.resource, e.stat);
129
+ }
130
+ shouldTrackHistoryFromFileOperationEvent(e) {
131
+ if (!e.isOperation(2 )) {
132
+ return false;
133
+ }
134
+ return this.shouldTrackHistory(e.target.resource, e.target);
135
+ }
136
+ shouldTrackHistory(resource, stat) {
137
+ if (resource.scheme !== this.pathService.defaultUriScheme &&
138
+ resource.scheme !== Schemas.vscodeUserData &&
139
+ resource.scheme !== Schemas.inMemory
140
+ ) {
141
+ return false;
142
+ }
143
+ const configuredMaxFileSizeInBytes = 1024 * this.configurationService.getValue(WorkingCopyHistoryTracker_1.SETTINGS.SIZE_LIMIT, { resource });
144
+ if (stat.size > configuredMaxFileSizeInBytes) {
145
+ return false;
146
+ }
147
+ if (this.configurationService.getValue(WorkingCopyHistoryTracker_1.SETTINGS.ENABLED, { resource }) === false) {
148
+ return false;
149
+ }
150
+ return !this.resourceExcludeMatcher.value.matches(resource);
151
+ }
152
+ };
153
+ WorkingCopyHistoryTracker = WorkingCopyHistoryTracker_1 = ( __decorate([
154
+ ( __param(0, IWorkingCopyService)),
155
+ ( __param(1, IWorkingCopyHistoryService)),
156
+ ( __param(2, IUriIdentityService)),
157
+ ( __param(3, IPathService)),
158
+ ( __param(4, IConfigurationService)),
159
+ ( __param(5, IUndoRedoService)),
160
+ ( __param(6, IWorkspaceContextService)),
161
+ ( __param(7, IFileService))
162
+ ], WorkingCopyHistoryTracker));
163
+
164
+ export { WorkingCopyHistoryTracker };
package/workingCopy.js CHANGED
@@ -3,6 +3,8 @@ import { BrowserWorkingCopyBackupService } from './vscode/src/vs/workbench/servi
3
3
  import { IWorkingCopyBackupService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyBackup';
4
4
  import { IWorkingCopyService, WorkingCopyService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyService';
5
5
  import { IWorkingCopyEditorService, WorkingCopyEditorService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyEditorService';
6
+ import { IWorkingCopyHistoryService } from 'vscode/vscode/vs/workbench/services/workingCopy/common/workingCopyHistory';
7
+ import { BrowserWorkingCopyHistoryService } from './vscode/src/vs/workbench/services/workingCopy/browser/workingCopyHistoryService.js';
6
8
  import getServiceOverride$1 from '@codingame/monaco-vscode-files-service-override';
7
9
 
8
10
  function getServiceOverride() {
@@ -10,7 +12,8 @@ function getServiceOverride() {
10
12
  ...getServiceOverride$1(),
11
13
  [( IWorkingCopyBackupService.toString())]: new SyncDescriptor(BrowserWorkingCopyBackupService, [], false),
12
14
  [( IWorkingCopyService.toString())]: new SyncDescriptor(WorkingCopyService, [], false),
13
- [( IWorkingCopyEditorService.toString())]: new SyncDescriptor(WorkingCopyEditorService, [], false)
15
+ [( IWorkingCopyEditorService.toString())]: new SyncDescriptor(WorkingCopyEditorService, [], false),
16
+ [( IWorkingCopyHistoryService.toString())]: new SyncDescriptor(BrowserWorkingCopyHistoryService, [], false)
14
17
  };
15
18
  }
16
19