@codingame/monaco-vscode-edit-sessions-service-override 2.2.0-next.1

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,1197 @@
1
+ import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
2
+ import { Disposable, MutableDisposable } from 'vscode/vscode/vs/base/common/lifecycle';
3
+ import { Extensions as Extensions$1 } from 'vscode/vscode/vs/workbench/common/contributions';
4
+ import { Registry } from 'vscode/vscode/vs/platform/registry/common/platform';
5
+ import { ILifecycleService } from 'vscode/vscode/vs/workbench/services/lifecycle/common/lifecycle';
6
+ import { registerAction2, Action2, MenuRegistry, MenuId } from 'vscode/vscode/vs/platform/actions/common/actions';
7
+ import { localize2WithPath, localizeWithPath } from 'vscode/vscode/vs/nls';
8
+ import { EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_PENDING, EDIT_SESSIONS_CONTAINER_ID, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_VIEW_ICON, editSessionsLogId, EDIT_SESSIONS_DATA_VIEW_ID, hashedEditSessionId, EditSessionSchemaVersion, ChangeType, decodeEditSessionFileContent, FileType, IEditSessionsStorageService, IEditSessionsLogService } from 'vscode/vscode/vs/workbench/contrib/editSessions/common/editSessions';
9
+ import { ISCMService } from 'vscode/vscode/vs/workbench/contrib/scm/common/scm';
10
+ import { IFileService } from 'vscode/vscode/vs/platform/files/common/files';
11
+ import { IWorkspaceContextService } from 'vscode/vscode/vs/platform/workspace/common/workspace';
12
+ import { URI } from 'vscode/vscode/vs/base/common/uri';
13
+ import { basename, joinPath, relativePath } from 'vscode/vscode/vs/base/common/resources';
14
+ import { encodeBase64 } from 'vscode/vscode/vs/base/common/buffer';
15
+ import { IConfigurationService } from 'vscode/vscode/vs/platform/configuration/common/configuration';
16
+ import { IProgressService } from 'vscode/vscode/vs/platform/progress/common/progress';
17
+ import { UserDataSyncStoreError } from 'vscode/vscode/vs/platform/userDataSync/common/userDataSync';
18
+ import { ITelemetryService } from 'vscode/vscode/vs/platform/telemetry/common/telemetry';
19
+ import { Severity, INotificationService } from 'vscode/vscode/vs/platform/notification/common/notification';
20
+ import '../../../../../../../override/vs/platform/dialogs/common/dialogs.js';
21
+ import { IProductService } from 'vscode/vscode/vs/platform/product/common/productService';
22
+ import { IOpenerService } from 'vscode/vscode/vs/platform/opener/common/opener';
23
+ import { IEnvironmentService } from 'vscode/vscode/vs/platform/environment/common/environment';
24
+ import { workbenchConfigurationNodeBase } from 'vscode/vscode/vs/workbench/common/configuration';
25
+ import { Extensions as Extensions$2 } from 'vscode/vscode/vs/platform/configuration/common/configurationRegistry';
26
+ import { IQuickInputService } from 'vscode/vscode/vs/platform/quickinput/common/quickInput';
27
+ import { ExtensionsRegistry } from 'vscode/vscode/vs/workbench/services/extensions/common/extensionsRegistry';
28
+ import { ContextKeyExpr, IContextKeyService } from 'vscode/vscode/vs/platform/contextkey/common/contextkey';
29
+ import { ICommandService } from 'vscode/vscode/vs/platform/commands/common/commands';
30
+ import { getVirtualWorkspaceLocation } from 'vscode/vscode/vs/platform/workspace/common/virtualWorkspace';
31
+ import { Schemas } from 'vscode/vscode/vs/base/common/network';
32
+ import { IsWebContext } from 'vscode/vscode/vs/platform/contextkey/common/contextkeys';
33
+ import { isProposedApiEnabled, IExtensionService } from 'vscode/vscode/vs/workbench/services/extensions/common/extensions';
34
+ import { Extensions } from 'vscode/vscode/vs/workbench/common/views';
35
+ import { IViewsService } from 'vscode/vscode/vs/workbench/services/views/common/viewsService';
36
+ import { SyncDescriptor } from 'vscode/vscode/vs/platform/instantiation/common/descriptors';
37
+ import { ViewPaneContainer } from 'vscode/vscode/vs/workbench/browser/parts/views/viewPaneContainer';
38
+ import { IInstantiationService } from 'vscode/vscode/vs/platform/instantiation/common/instantiation';
39
+ import { EditSessionsDataViews } from './editSessionsViews.js';
40
+ import { EditSessionsFileSystemProvider } from './editSessionsFileSystemProvider.js';
41
+ import { isWeb, isNative } from 'vscode/vscode/vs/base/common/platform';
42
+ import { WorkspaceFolderCountContext, VirtualWorkspaceContext } from 'vscode/vscode/vs/workbench/common/contextkeys';
43
+ import { CancellationTokenSource } from 'vscode/vscode/vs/base/common/cancellation';
44
+ import { equals } from 'vscode/vscode/vs/base/common/objects';
45
+ import { EditSessionIdentityMatch, IEditSessionIdentityService } from 'vscode/vscode/vs/platform/workspace/common/editSessions';
46
+ import { ThemeIcon } from 'vscode/vscode/vs/base/common/themables';
47
+ import { IOutputService } from 'vscode/vscode/vs/workbench/services/output/common/output';
48
+ import { sha1Hex } from '../../../../base/browser/hash.js';
49
+ import { IStorageService } from 'vscode/vscode/vs/platform/storage/common/storage';
50
+ import { NumberBadge, IActivityService } from 'vscode/vscode/vs/workbench/services/activity/common/activity';
51
+ import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService';
52
+ import { Codicon } from 'vscode/vscode/vs/base/common/codicons';
53
+ import { CancellationError } from 'vscode/vscode/vs/base/common/errors';
54
+ import { IRemoteAgentService } from 'vscode/vscode/vs/workbench/services/remote/common/remoteAgentService';
55
+ import { VIEWLET_ID } from 'vscode/vscode/vs/workbench/contrib/extensions/common/extensions';
56
+ import { IPaneCompositePartService } from 'vscode/vscode/vs/workbench/services/panecomposite/browser/panecomposite';
57
+ import { WorkspaceStateSynchroniser } from '../common/workspaceStateSync.js';
58
+ import { IUserDataProfilesService } from 'vscode/vscode/vs/platform/userDataProfile/common/userDataProfile';
59
+ import { IRequestService } from 'vscode/vscode/vs/platform/request/common/request';
60
+ import { EditSessionsStoreClient } from '../common/editSessionsStorageClient.js';
61
+ import { IUriIdentityService } from 'vscode/vscode/vs/platform/uriIdentity/common/uriIdentity';
62
+ import { IWorkspaceIdentityService } from '../../../services/workspaces/common/workspaceIdentityService.js';
63
+ import { getFileNamesMessage, IDialogService, IFileDialogService } from 'vscode/vscode/vs/platform/dialogs/common/dialogs';
64
+
65
+ var EditSessionsContribution_1;
66
+ const continueWorkingOnCommand = {
67
+ id: '_workbench.editSessions.actions.continueEditSession',
68
+ title: ( localize2WithPath(
69
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
70
+ 'continue working on',
71
+ 'Continue Working On...'
72
+ )),
73
+ precondition: ( WorkspaceFolderCountContext.notEqualsTo('0')),
74
+ f1: true
75
+ };
76
+ const openLocalFolderCommand = {
77
+ id: '_workbench.editSessions.actions.continueEditSession.openLocalFolder',
78
+ title: ( localize2WithPath(
79
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
80
+ 'continue edit session in local folder',
81
+ 'Open In Local Folder'
82
+ )),
83
+ category: EDIT_SESSION_SYNC_CATEGORY,
84
+ precondition: ( ContextKeyExpr.and(( IsWebContext.toNegated()), VirtualWorkspaceContext))
85
+ };
86
+ const showOutputChannelCommand = {
87
+ id: 'workbench.editSessions.actions.showOutputChannel',
88
+ title: { value: ( localizeWithPath(
89
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
90
+ 'show log',
91
+ 'Show Log'
92
+ )), original: 'Show Log' },
93
+ category: EDIT_SESSION_SYNC_CATEGORY
94
+ };
95
+ const installAdditionalContinueOnOptionsCommand = {
96
+ id: 'workbench.action.continueOn.extensions',
97
+ title: ( localizeWithPath(
98
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
99
+ 'continueOn.installAdditional',
100
+ 'Install additional development environment options'
101
+ )),
102
+ };
103
+ registerAction2(class extends Action2 {
104
+ constructor() {
105
+ super({ ...installAdditionalContinueOnOptionsCommand, f1: false });
106
+ }
107
+ async run(accessor) {
108
+ const paneCompositePartService = accessor.get(IPaneCompositePartService);
109
+ const viewlet = await paneCompositePartService.openPaneComposite(VIEWLET_ID, 0 , true);
110
+ const view = viewlet?.getViewPaneContainer();
111
+ view?.search('@tag:continueOn');
112
+ }
113
+ });
114
+ const resumeProgressOptionsTitle = `[${( localizeWithPath(
115
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
116
+ 'resuming working changes window',
117
+ 'Resuming working changes...'
118
+ ))}](command:${showOutputChannelCommand.id})`;
119
+ const resumeProgressOptions = {
120
+ location: 10 ,
121
+ type: 'syncing',
122
+ };
123
+ const queryParamName = 'editSessionId';
124
+ const useEditSessionsWithContinueOn = 'workbench.editSessions.continueOn';
125
+ let EditSessionsContribution = class EditSessionsContribution extends Disposable {
126
+ static { EditSessionsContribution_1 = this; }
127
+ static { this.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY = 'applicationLaunchedViaContinueOn'; }
128
+ constructor(editSessionsStorageService, fileService, progressService, openerService, telemetryService, scmService, notificationService, dialogService, logService, environmentService, instantiationService, productService, configurationService, contextService, editSessionIdentityService, quickInputService, commandService, contextKeyService, fileDialogService, lifecycleService, storageService, activityService, editorService, remoteAgentService, extensionService, requestService, userDataProfilesService, uriIdentityService, workspaceIdentityService) {
129
+ super();
130
+ this.editSessionsStorageService = editSessionsStorageService;
131
+ this.fileService = fileService;
132
+ this.progressService = progressService;
133
+ this.openerService = openerService;
134
+ this.telemetryService = telemetryService;
135
+ this.scmService = scmService;
136
+ this.notificationService = notificationService;
137
+ this.dialogService = dialogService;
138
+ this.logService = logService;
139
+ this.environmentService = environmentService;
140
+ this.instantiationService = instantiationService;
141
+ this.productService = productService;
142
+ this.configurationService = configurationService;
143
+ this.contextService = contextService;
144
+ this.editSessionIdentityService = editSessionIdentityService;
145
+ this.quickInputService = quickInputService;
146
+ this.commandService = commandService;
147
+ this.contextKeyService = contextKeyService;
148
+ this.fileDialogService = fileDialogService;
149
+ this.lifecycleService = lifecycleService;
150
+ this.storageService = storageService;
151
+ this.activityService = activityService;
152
+ this.editorService = editorService;
153
+ this.remoteAgentService = remoteAgentService;
154
+ this.extensionService = extensionService;
155
+ this.requestService = requestService;
156
+ this.userDataProfilesService = userDataProfilesService;
157
+ this.uriIdentityService = uriIdentityService;
158
+ this.workspaceIdentityService = workspaceIdentityService;
159
+ this.continueEditSessionOptions = [];
160
+ this.accountsMenuBadgeDisposable = this._register(( new MutableDisposable()));
161
+ this.registeredCommands = ( new Set());
162
+ this.shouldShowViewsContext = EDIT_SESSIONS_SHOW_VIEW.bindTo(this.contextKeyService);
163
+ this.pendingEditSessionsContext = EDIT_SESSIONS_PENDING.bindTo(this.contextKeyService);
164
+ this.pendingEditSessionsContext.set(false);
165
+ if (!this.productService['editSessions.store']?.url) {
166
+ return;
167
+ }
168
+ this.editSessionsStorageClient = ( new EditSessionsStoreClient(( URI.parse(this.productService['editSessions.store'].url)), this.productService, this.requestService, this.logService, this.environmentService, this.fileService, this.storageService));
169
+ this.editSessionsStorageService.storeClient = this.editSessionsStorageClient;
170
+ this.workspaceStateSynchronizer = ( new WorkspaceStateSynchroniser(
171
+ this.userDataProfilesService.defaultProfile,
172
+ undefined,
173
+ this.editSessionsStorageClient,
174
+ this.logService,
175
+ this.fileService,
176
+ this.environmentService,
177
+ this.telemetryService,
178
+ this.configurationService,
179
+ this.storageService,
180
+ this.uriIdentityService,
181
+ this.workspaceIdentityService,
182
+ this.editSessionsStorageService
183
+ ));
184
+ this.autoResumeEditSession();
185
+ this.registerActions();
186
+ this.registerViews();
187
+ this.registerContributedEditSessionOptions();
188
+ this._register(this.fileService.registerProvider(EditSessionsFileSystemProvider.SCHEMA, ( new EditSessionsFileSystemProvider(this.editSessionsStorageService))));
189
+ this.lifecycleService.onWillShutdown((e) => {
190
+ if (e.reason !== 3 && this.editSessionsStorageService.isSignedIn && this.configurationService.getValue('workbench.experimental.cloudChanges.autoStore') === 'onShutdown' && !isWeb) {
191
+ e.join(this.autoStoreEditSession(), { id: 'autoStoreWorkingChanges', label: ( localizeWithPath(
192
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
193
+ 'autoStoreWorkingChanges',
194
+ 'Storing current working changes...'
195
+ )) });
196
+ }
197
+ });
198
+ this._register(this.editSessionsStorageService.onDidSignIn(() => this.updateAccountsMenuBadge()));
199
+ this._register(this.editSessionsStorageService.onDidSignOut(() => this.updateAccountsMenuBadge()));
200
+ }
201
+ async autoResumeEditSession() {
202
+ const shouldAutoResumeOnReload = this.configurationService.getValue('workbench.cloudChanges.autoResume') === 'onReload';
203
+ if (this.environmentService.editSessionId !== undefined) {
204
+ this.logService.info(`Resuming cloud changes, reason: found editSessionId ${this.environmentService.editSessionId} in environment service...`);
205
+ await this.progressService.withProgress(resumeProgressOptions, async (progress) => await this.resumeEditSession(this.environmentService.editSessionId, undefined, undefined, undefined, progress).finally(() => this.environmentService.editSessionId = undefined));
206
+ }
207
+ else if (shouldAutoResumeOnReload && this.editSessionsStorageService.isSignedIn) {
208
+ this.logService.info('Resuming cloud changes, reason: cloud changes enabled...');
209
+ await this.progressService.withProgress(resumeProgressOptions, async (progress) => await this.resumeEditSession(undefined, true, undefined, undefined, progress));
210
+ }
211
+ else if (shouldAutoResumeOnReload) {
212
+ const hasApplicationLaunchedFromContinueOnFlow = this.storageService.getBoolean(EditSessionsContribution_1.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, -1 , false);
213
+ this.logService.info(`Prompting to enable cloud changes, has application previously launched from Continue On flow: ${hasApplicationLaunchedFromContinueOnFlow}`);
214
+ const handlePendingEditSessions = () => {
215
+ this.logService.info('Showing badge to enable cloud changes in accounts menu...');
216
+ this.updateAccountsMenuBadge();
217
+ this.pendingEditSessionsContext.set(true);
218
+ const disposable = this.editSessionsStorageService.onDidSignIn(async () => {
219
+ disposable.dispose();
220
+ this.logService.info('Showing badge to enable cloud changes in accounts menu succeeded, resuming cloud changes...');
221
+ await this.progressService.withProgress(resumeProgressOptions, async (progress) => await this.resumeEditSession(undefined, true, undefined, undefined, progress));
222
+ this.storageService.remove(EditSessionsContribution_1.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, -1 );
223
+ this.environmentService.continueOn = undefined;
224
+ });
225
+ };
226
+ if ((this.environmentService.continueOn !== undefined) &&
227
+ !this.editSessionsStorageService.isSignedIn &&
228
+ hasApplicationLaunchedFromContinueOnFlow === false) {
229
+ this.storageService.store(EditSessionsContribution_1.APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY, true, -1 , 1 );
230
+ this.logService.info('Prompting to enable cloud changes...');
231
+ await this.editSessionsStorageService.initialize('read');
232
+ if (this.editSessionsStorageService.isSignedIn) {
233
+ this.logService.info('Prompting to enable cloud changes succeeded, resuming cloud changes...');
234
+ await this.progressService.withProgress(resumeProgressOptions, async (progress) => await this.resumeEditSession(undefined, true, undefined, undefined, progress));
235
+ }
236
+ else {
237
+ handlePendingEditSessions();
238
+ }
239
+ }
240
+ else if (!this.editSessionsStorageService.isSignedIn &&
241
+ hasApplicationLaunchedFromContinueOnFlow === true) {
242
+ handlePendingEditSessions();
243
+ }
244
+ }
245
+ else {
246
+ this.logService.debug('Auto resuming cloud changes disabled.');
247
+ }
248
+ }
249
+ updateAccountsMenuBadge() {
250
+ if (this.editSessionsStorageService.isSignedIn) {
251
+ return this.accountsMenuBadgeDisposable.clear();
252
+ }
253
+ const badge = ( new NumberBadge(1, () => ( localizeWithPath(
254
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
255
+ 'check for pending cloud changes',
256
+ 'Check for pending cloud changes'
257
+ ))));
258
+ this.accountsMenuBadgeDisposable.value = this.activityService.showAccountsActivity({ badge });
259
+ }
260
+ async autoStoreEditSession() {
261
+ const cancellationTokenSource = ( new CancellationTokenSource());
262
+ await this.progressService.withProgress({
263
+ location: 10 ,
264
+ type: 'syncing',
265
+ title: ( localizeWithPath(
266
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
267
+ 'store working changes',
268
+ 'Storing working changes...'
269
+ ))
270
+ }, async () => this.storeEditSession(false, cancellationTokenSource.token), () => {
271
+ cancellationTokenSource.cancel();
272
+ cancellationTokenSource.dispose();
273
+ });
274
+ }
275
+ registerViews() {
276
+ const container = ( Registry.as(Extensions.ViewContainersRegistry)).registerViewContainer({
277
+ id: EDIT_SESSIONS_CONTAINER_ID,
278
+ title: EDIT_SESSIONS_TITLE,
279
+ ctorDescriptor: ( new SyncDescriptor(
280
+ ViewPaneContainer,
281
+ [EDIT_SESSIONS_CONTAINER_ID, { mergeViewWithContainerWhenSingleView: true }]
282
+ )),
283
+ icon: EDIT_SESSIONS_VIEW_ICON,
284
+ hideIfEmpty: true
285
+ }, 0 , { doNotRegisterOpenCommand: true });
286
+ this._register(this.instantiationService.createInstance(EditSessionsDataViews, container));
287
+ }
288
+ registerActions() {
289
+ this.registerContinueEditSessionAction();
290
+ this.registerResumeLatestEditSessionAction();
291
+ this.registerStoreLatestEditSessionAction();
292
+ this.registerContinueInLocalFolderAction();
293
+ this.registerShowEditSessionViewAction();
294
+ this.registerShowEditSessionOutputChannelAction();
295
+ }
296
+ registerShowEditSessionOutputChannelAction() {
297
+ this._register(registerAction2(class ShowEditSessionOutput extends Action2 {
298
+ constructor() {
299
+ super(showOutputChannelCommand);
300
+ }
301
+ run(accessor, ...args) {
302
+ const outputChannel = accessor.get(IOutputService);
303
+ void outputChannel.showChannel(editSessionsLogId);
304
+ }
305
+ }));
306
+ }
307
+ registerShowEditSessionViewAction() {
308
+ const that = this;
309
+ this._register(registerAction2(class ShowEditSessionView extends Action2 {
310
+ constructor() {
311
+ super({
312
+ id: 'workbench.editSessions.actions.showEditSessions',
313
+ title: ( localize2WithPath(
314
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
315
+ 'show cloud changes',
316
+ 'Show Cloud Changes'
317
+ )),
318
+ category: EDIT_SESSION_SYNC_CATEGORY,
319
+ f1: true
320
+ });
321
+ }
322
+ async run(accessor) {
323
+ that.shouldShowViewsContext.set(true);
324
+ const viewsService = accessor.get(IViewsService);
325
+ await viewsService.openView(EDIT_SESSIONS_DATA_VIEW_ID);
326
+ }
327
+ }));
328
+ }
329
+ registerContinueEditSessionAction() {
330
+ const that = this;
331
+ this._register(registerAction2(class ContinueEditSessionAction extends Action2 {
332
+ constructor() {
333
+ super(continueWorkingOnCommand);
334
+ }
335
+ async run(accessor, workspaceUri, destination) {
336
+ let uri = workspaceUri;
337
+ if (!destination && !uri) {
338
+ destination = await that.pickContinueEditSessionDestination();
339
+ if (!destination) {
340
+ that.telemetryService.publicLog2('continueOn.editSessions.pick.outcome', { outcome: 'noSelection' });
341
+ return;
342
+ }
343
+ }
344
+ const shouldStoreEditSession = await that.shouldContinueOnWithEditSession();
345
+ let ref;
346
+ if (shouldStoreEditSession) {
347
+ that.telemetryService.publicLog2('continueOn.editSessions.store');
348
+ const cancellationTokenSource = ( new CancellationTokenSource());
349
+ try {
350
+ ref = await that.progressService.withProgress({
351
+ location: 15 ,
352
+ cancellable: true,
353
+ type: 'syncing',
354
+ title: ( localizeWithPath(
355
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
356
+ 'store your working changes',
357
+ 'Storing your working changes...'
358
+ ))
359
+ }, async () => {
360
+ const ref = await that.storeEditSession(false, cancellationTokenSource.token);
361
+ if (ref !== undefined) {
362
+ that.telemetryService.publicLog2('continueOn.editSessions.store.outcome', { outcome: 'storeSucceeded', hashedId: hashedEditSessionId(ref) });
363
+ }
364
+ else {
365
+ that.telemetryService.publicLog2('continueOn.editSessions.store.outcome', { outcome: 'storeSkipped' });
366
+ }
367
+ return ref;
368
+ }, () => {
369
+ cancellationTokenSource.cancel();
370
+ cancellationTokenSource.dispose();
371
+ that.telemetryService.publicLog2('continueOn.editSessions.store.outcome', { outcome: 'storeCancelledByUser' });
372
+ });
373
+ }
374
+ catch (ex) {
375
+ that.telemetryService.publicLog2('continueOn.editSessions.store.outcome', { outcome: 'storeFailed' });
376
+ throw ex;
377
+ }
378
+ }
379
+ uri = destination ? await that.resolveDestination(destination) : uri;
380
+ if (uri === undefined) {
381
+ return;
382
+ }
383
+ if (ref !== undefined && uri !== 'noDestinationUri') {
384
+ const encodedRef = encodeURIComponent(ref);
385
+ uri = uri.with({
386
+ query: uri.query.length > 0 ? (uri.query + `&${queryParamName}=${encodedRef}&continueOn=1`) : `${queryParamName}=${encodedRef}&continueOn=1`
387
+ });
388
+ that.logService.info(`Opening ${( uri.toString())}`);
389
+ await that.openerService.open(uri, { openExternal: true });
390
+ }
391
+ else if (!shouldStoreEditSession && uri !== 'noDestinationUri') {
392
+ that.logService.info(`Opening ${( uri.toString())}`);
393
+ await that.openerService.open(uri, { openExternal: true });
394
+ }
395
+ else if (ref === undefined && shouldStoreEditSession) {
396
+ that.logService.warn(`Failed to store working changes when invoking ${continueWorkingOnCommand.id}.`);
397
+ }
398
+ }
399
+ }));
400
+ }
401
+ registerResumeLatestEditSessionAction() {
402
+ const that = this;
403
+ this._register(registerAction2(class ResumeLatestEditSessionAction extends Action2 {
404
+ constructor() {
405
+ super({
406
+ id: 'workbench.editSessions.actions.resumeLatest',
407
+ title: ( localize2WithPath(
408
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
409
+ 'resume latest cloud changes',
410
+ 'Resume Latest Changes from Cloud'
411
+ )),
412
+ category: EDIT_SESSION_SYNC_CATEGORY,
413
+ f1: true,
414
+ });
415
+ }
416
+ async run(accessor, editSessionId, forceApplyUnrelatedChange) {
417
+ await that.progressService.withProgress({ ...resumeProgressOptions, title: resumeProgressOptionsTitle }, async () => await that.resumeEditSession(editSessionId, undefined, forceApplyUnrelatedChange));
418
+ }
419
+ }));
420
+ this._register(registerAction2(class ResumeLatestEditSessionAction extends Action2 {
421
+ constructor() {
422
+ super({
423
+ id: 'workbench.editSessions.actions.resumeFromSerializedPayload',
424
+ title: ( localize2WithPath(
425
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
426
+ 'resume cloud changes',
427
+ 'Resume Changes from Serialized Data'
428
+ )),
429
+ category: 'Developer',
430
+ f1: true,
431
+ });
432
+ }
433
+ async run(accessor, editSessionId) {
434
+ const data = await that.quickInputService.input({ prompt: 'Enter serialized data' });
435
+ if (data) {
436
+ that.editSessionsStorageService.lastReadResources.set('editSessions', { content: data, ref: '' });
437
+ }
438
+ await that.progressService.withProgress({ ...resumeProgressOptions, title: resumeProgressOptionsTitle }, async () => await that.resumeEditSession(editSessionId, undefined, undefined, undefined, undefined, data));
439
+ }
440
+ }));
441
+ }
442
+ registerStoreLatestEditSessionAction() {
443
+ const that = this;
444
+ this._register(registerAction2(class StoreLatestEditSessionAction extends Action2 {
445
+ constructor() {
446
+ super({
447
+ id: 'workbench.editSessions.actions.storeCurrent',
448
+ title: ( localize2WithPath(
449
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
450
+ 'store working changes in cloud',
451
+ 'Store Working Changes in Cloud'
452
+ )),
453
+ category: EDIT_SESSION_SYNC_CATEGORY,
454
+ f1: true,
455
+ });
456
+ }
457
+ async run(accessor) {
458
+ const cancellationTokenSource = ( new CancellationTokenSource());
459
+ await that.progressService.withProgress({
460
+ location: 15 ,
461
+ title: ( localizeWithPath(
462
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
463
+ 'storing working changes',
464
+ 'Storing working changes...'
465
+ ))
466
+ }, async () => {
467
+ that.telemetryService.publicLog2('editSessions.store');
468
+ await that.storeEditSession(true, cancellationTokenSource.token);
469
+ }, () => {
470
+ cancellationTokenSource.cancel();
471
+ cancellationTokenSource.dispose();
472
+ });
473
+ }
474
+ }));
475
+ }
476
+ async resumeEditSession(ref, silent, forceApplyUnrelatedChange, applyPartialMatch, progress, serializedData) {
477
+ await this.remoteAgentService.getEnvironment();
478
+ if (this.contextService.getWorkbenchState() === 1 ) {
479
+ return;
480
+ }
481
+ this.logService.info(ref !== undefined ? `Resuming changes from cloud with ref ${ref}...` : 'Checking for pending cloud changes...');
482
+ if (silent && !(await this.editSessionsStorageService.initialize('read', true))) {
483
+ return;
484
+ }
485
+ this.telemetryService.publicLog2('editSessions.resume');
486
+ performance.mark('code/willResumeEditSessionFromIdentifier');
487
+ progress?.report({ message: ( localizeWithPath(
488
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
489
+ 'checkingForWorkingChanges',
490
+ 'Checking for pending cloud changes...'
491
+ )) });
492
+ const data = serializedData ? { content: serializedData, ref: '' } : await this.editSessionsStorageService.read('editSessions', ref);
493
+ if (!data) {
494
+ if (ref === undefined && !silent) {
495
+ this.notificationService.info(( localizeWithPath(
496
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
497
+ 'no cloud changes',
498
+ 'There are no changes to resume from the cloud.'
499
+ )));
500
+ }
501
+ else if (ref !== undefined) {
502
+ this.notificationService.warn(( localizeWithPath(
503
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
504
+ 'no cloud changes for ref',
505
+ 'Could not resume changes from the cloud for ID {0}.',
506
+ ref
507
+ )));
508
+ }
509
+ this.logService.info(ref !== undefined ? `Aborting resuming changes from cloud as no edit session content is available to be applied from ref ${ref}.` : `Aborting resuming edit session as no edit session content is available to be applied`);
510
+ return;
511
+ }
512
+ progress?.report({ message: resumeProgressOptionsTitle });
513
+ const editSession = JSON.parse(data.content);
514
+ ref = data.ref;
515
+ if (editSession.version > EditSessionSchemaVersion) {
516
+ this.notificationService.error(( localizeWithPath(
517
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
518
+ 'client too old',
519
+ "Please upgrade to a newer version of {0} to resume your working changes from the cloud.",
520
+ this.productService.nameLong
521
+ )));
522
+ this.telemetryService.publicLog2('editSessions.resume.outcome', { hashedId: hashedEditSessionId(ref), outcome: 'clientUpdateNeeded' });
523
+ return;
524
+ }
525
+ try {
526
+ const { changes, conflictingChanges } = await this.generateChanges(editSession, ref, forceApplyUnrelatedChange, applyPartialMatch);
527
+ if (changes.length === 0) {
528
+ return;
529
+ }
530
+ if (conflictingChanges.length > 0) {
531
+ const { confirmed } = await this.dialogService.confirm({
532
+ type: Severity.Warning,
533
+ message: conflictingChanges.length > 1 ?
534
+ ( localizeWithPath(
535
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
536
+ 'resume edit session warning many',
537
+ 'Resuming your working changes from the cloud will overwrite the following {0} files. Do you want to proceed?',
538
+ conflictingChanges.length
539
+ )) :
540
+ ( localizeWithPath(
541
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
542
+ 'resume edit session warning 1',
543
+ 'Resuming your working changes from the cloud will overwrite {0}. Do you want to proceed?',
544
+ basename(conflictingChanges[0].uri)
545
+ )),
546
+ detail: conflictingChanges.length > 1 ? getFileNamesMessage(( conflictingChanges.map((c) => c.uri))) : undefined
547
+ });
548
+ if (!confirmed) {
549
+ return;
550
+ }
551
+ }
552
+ for (const { uri, type, contents } of changes) {
553
+ if (type === ChangeType.Addition) {
554
+ await this.fileService.writeFile(uri, decodeEditSessionFileContent(editSession.version, contents));
555
+ }
556
+ else if (type === ChangeType.Deletion && (await this.fileService.exists(uri))) {
557
+ await this.fileService.del(uri);
558
+ }
559
+ }
560
+ await this.workspaceStateSynchronizer?.apply(false, {});
561
+ this.logService.info(`Deleting edit session with ref ${ref} after successfully applying it to current workspace...`);
562
+ await this.editSessionsStorageService.delete('editSessions', ref);
563
+ this.logService.info(`Deleted edit session with ref ${ref}.`);
564
+ this.telemetryService.publicLog2('editSessions.resume.outcome', { hashedId: hashedEditSessionId(ref), outcome: 'resumeSucceeded' });
565
+ }
566
+ catch (ex) {
567
+ this.logService.error('Failed to resume edit session, reason: ', ( ex.toString()));
568
+ this.notificationService.error(( localizeWithPath(
569
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
570
+ 'resume failed',
571
+ "Failed to resume your working changes from the cloud."
572
+ )));
573
+ }
574
+ performance.mark('code/didResumeEditSessionFromIdentifier');
575
+ }
576
+ async generateChanges(editSession, ref, forceApplyUnrelatedChange = false, applyPartialMatch = false) {
577
+ const changes = [];
578
+ const conflictingChanges = [];
579
+ const workspaceFolders = this.contextService.getWorkspace().folders;
580
+ const cancellationTokenSource = ( new CancellationTokenSource());
581
+ for (const folder of editSession.folders) {
582
+ let folderRoot;
583
+ if (folder.canonicalIdentity) {
584
+ for (const f of workspaceFolders) {
585
+ const identity = await this.editSessionIdentityService.getEditSessionIdentifier(f, cancellationTokenSource.token);
586
+ this.logService.info(`Matching identity ${identity} against edit session folder identity ${folder.canonicalIdentity}...`);
587
+ if (equals(identity, folder.canonicalIdentity) || forceApplyUnrelatedChange) {
588
+ folderRoot = f;
589
+ break;
590
+ }
591
+ if (identity !== undefined) {
592
+ const match = await this.editSessionIdentityService.provideEditSessionIdentityMatch(f, identity, folder.canonicalIdentity, cancellationTokenSource.token);
593
+ if (match === EditSessionIdentityMatch.Complete) {
594
+ folderRoot = f;
595
+ break;
596
+ }
597
+ else if (match === EditSessionIdentityMatch.Partial &&
598
+ this.configurationService.getValue('workbench.experimental.cloudChanges.partialMatches.enabled') === true) {
599
+ if (!applyPartialMatch) {
600
+ this.notificationService.prompt(Severity.Info, ( localizeWithPath(
601
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
602
+ 'editSessionPartialMatch',
603
+ 'You have pending working changes in the cloud for this workspace. Would you like to resume them?'
604
+ )), [{ label: ( localizeWithPath(
605
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
606
+ 'resume',
607
+ 'Resume'
608
+ )), run: () => this.resumeEditSession(ref, false, undefined, true) }]);
609
+ }
610
+ else {
611
+ folderRoot = f;
612
+ break;
613
+ }
614
+ }
615
+ }
616
+ }
617
+ }
618
+ else {
619
+ folderRoot = workspaceFolders.find((f) => f.name === folder.name);
620
+ }
621
+ if (!folderRoot) {
622
+ this.logService.info(`Skipping applying ${folder.workingChanges.length} changes from edit session with ref ${ref} as no matching workspace folder was found.`);
623
+ return { changes: [], conflictingChanges: [], contributedStateHandlers: [] };
624
+ }
625
+ const localChanges = ( new Set());
626
+ for (const repository of this.scmService.repositories) {
627
+ if (repository.provider.rootUri !== undefined &&
628
+ this.contextService.getWorkspaceFolder(repository.provider.rootUri)?.name === folder.name) {
629
+ const repositoryChanges = this.getChangedResources(repository);
630
+ repositoryChanges.forEach((change) => localChanges.add(( change.toString())));
631
+ }
632
+ }
633
+ for (const change of folder.workingChanges) {
634
+ const uri = joinPath(folderRoot.uri, change.relativeFilePath);
635
+ changes.push({ uri, type: change.type, contents: change.contents });
636
+ if (await this.willChangeLocalContents(localChanges, uri, change)) {
637
+ conflictingChanges.push({ uri, type: change.type, contents: change.contents });
638
+ }
639
+ }
640
+ }
641
+ return { changes, conflictingChanges };
642
+ }
643
+ async willChangeLocalContents(localChanges, uriWithIncomingChanges, incomingChange) {
644
+ if (!( localChanges.has(( uriWithIncomingChanges.toString())))) {
645
+ return false;
646
+ }
647
+ const { contents, type } = incomingChange;
648
+ switch (type) {
649
+ case (ChangeType.Addition): {
650
+ const [originalContents, incomingContents] = await Promise.all([sha1Hex(contents), sha1Hex(encodeBase64((await this.fileService.readFile(uriWithIncomingChanges)).value))]);
651
+ return originalContents !== incomingContents;
652
+ }
653
+ case (ChangeType.Deletion): {
654
+ return await this.fileService.exists(uriWithIncomingChanges);
655
+ }
656
+ default:
657
+ throw new Error('Unhandled change type.');
658
+ }
659
+ }
660
+ async storeEditSession(fromStoreCommand, cancellationToken) {
661
+ const folders = [];
662
+ let editSessionSize = 0;
663
+ let hasEdits = false;
664
+ await this.editorService.saveAll();
665
+ for (const repository of this.scmService.repositories) {
666
+ const trackedUris = this.getChangedResources(repository);
667
+ const workingChanges = [];
668
+ const { rootUri } = repository.provider;
669
+ const workspaceFolder = rootUri ? this.contextService.getWorkspaceFolder(rootUri) : undefined;
670
+ let name = workspaceFolder?.name;
671
+ for (const uri of trackedUris) {
672
+ const workspaceFolder = this.contextService.getWorkspaceFolder(uri);
673
+ if (!workspaceFolder) {
674
+ this.logService.info(`Skipping working change ${( uri.toString())} as no associated workspace folder was found.`);
675
+ continue;
676
+ }
677
+ await this.editSessionIdentityService.onWillCreateEditSessionIdentity(workspaceFolder, cancellationToken);
678
+ name = name ?? workspaceFolder.name;
679
+ const relativeFilePath = relativePath(workspaceFolder.uri, uri) ?? uri.path;
680
+ try {
681
+ if (!(await this.fileService.stat(uri)).isFile) {
682
+ continue;
683
+ }
684
+ }
685
+ catch { }
686
+ hasEdits = true;
687
+ if (await this.fileService.exists(uri)) {
688
+ const contents = encodeBase64((await this.fileService.readFile(uri)).value);
689
+ editSessionSize += contents.length;
690
+ if (editSessionSize > this.editSessionsStorageService.SIZE_LIMIT) {
691
+ this.notificationService.error(( localizeWithPath(
692
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
693
+ 'payload too large',
694
+ 'Your working changes exceed the size limit and cannot be stored.'
695
+ )));
696
+ return undefined;
697
+ }
698
+ workingChanges.push({ type: ChangeType.Addition, fileType: FileType.File, contents: contents, relativeFilePath: relativeFilePath });
699
+ }
700
+ else {
701
+ workingChanges.push({ type: ChangeType.Deletion, fileType: FileType.File, contents: undefined, relativeFilePath: relativeFilePath });
702
+ }
703
+ }
704
+ let canonicalIdentity = undefined;
705
+ if (workspaceFolder !== null && workspaceFolder !== undefined) {
706
+ canonicalIdentity = await this.editSessionIdentityService.getEditSessionIdentifier(workspaceFolder, cancellationToken);
707
+ }
708
+ folders.push({ workingChanges, name: name ?? '', canonicalIdentity: canonicalIdentity ?? undefined, absoluteUri: workspaceFolder?.uri.toString() });
709
+ }
710
+ await this.workspaceStateSynchronizer?.sync(null, {});
711
+ if (!hasEdits) {
712
+ this.logService.info('Skipped storing working changes in the cloud as there are no edits to store.');
713
+ if (fromStoreCommand) {
714
+ this.notificationService.info(( localizeWithPath(
715
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
716
+ 'no working changes to store',
717
+ 'Skipped storing working changes in the cloud as there are no edits to store.'
718
+ )));
719
+ }
720
+ return undefined;
721
+ }
722
+ const data = { folders, version: 2, workspaceStateId: this.editSessionsStorageService.lastWrittenResources.get('workspaceState')?.ref };
723
+ try {
724
+ this.logService.info(`Storing edit session...`);
725
+ const ref = await this.editSessionsStorageService.write('editSessions', data);
726
+ this.logService.info(`Stored edit session with ref ${ref}.`);
727
+ return ref;
728
+ }
729
+ catch (ex) {
730
+ this.logService.error(`Failed to store edit session, reason: `, ( ex.toString()));
731
+ if (ex instanceof UserDataSyncStoreError) {
732
+ switch (ex.code) {
733
+ case "TooLarge" :
734
+ this.telemetryService.publicLog2('editSessions.upload.failed', { reason: 'TooLarge' });
735
+ this.notificationService.error(( localizeWithPath(
736
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
737
+ 'payload too large',
738
+ 'Your working changes exceed the size limit and cannot be stored.'
739
+ )));
740
+ break;
741
+ default:
742
+ this.telemetryService.publicLog2('editSessions.upload.failed', { reason: 'unknown' });
743
+ this.notificationService.error(( localizeWithPath(
744
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
745
+ 'payload failed',
746
+ 'Your working changes cannot be stored.'
747
+ )));
748
+ break;
749
+ }
750
+ }
751
+ }
752
+ return undefined;
753
+ }
754
+ getChangedResources(repository) {
755
+ return repository.provider.groups.reduce((resources, resourceGroups) => {
756
+ resourceGroups.resources.forEach((resource) => resources.add(resource.sourceUri));
757
+ return resources;
758
+ }, ( new Set()));
759
+ }
760
+ hasEditSession() {
761
+ for (const repository of this.scmService.repositories) {
762
+ if (this.getChangedResources(repository).size > 0) {
763
+ return true;
764
+ }
765
+ }
766
+ return false;
767
+ }
768
+ async shouldContinueOnWithEditSession() {
769
+ if (this.editSessionsStorageService.isSignedIn) {
770
+ return this.hasEditSession();
771
+ }
772
+ if (this.configurationService.getValue(useEditSessionsWithContinueOn) === 'off') {
773
+ this.telemetryService.publicLog2('continueOn.editSessions.canStore.outcome', { outcome: 'disabledEditSessionsViaSetting' });
774
+ return false;
775
+ }
776
+ if (this.hasEditSession()) {
777
+ const quickpick = this.quickInputService.createQuickPick();
778
+ quickpick.placeholder = ( localizeWithPath(
779
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
780
+ 'continue with cloud changes',
781
+ "Select whether to bring your working changes with you"
782
+ ));
783
+ quickpick.ok = false;
784
+ quickpick.ignoreFocusOut = true;
785
+ const withCloudChanges = { label: ( localizeWithPath(
786
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
787
+ 'with cloud changes',
788
+ "Yes, continue with my working changes"
789
+ )) };
790
+ const withoutCloudChanges = { label: ( localizeWithPath(
791
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
792
+ 'without cloud changes',
793
+ "No, continue without my working changes"
794
+ )) };
795
+ quickpick.items = [withCloudChanges, withoutCloudChanges];
796
+ const continueWithCloudChanges = await ( new Promise((resolve, reject) => {
797
+ quickpick.onDidAccept(() => {
798
+ resolve(quickpick.selectedItems[0] === withCloudChanges);
799
+ quickpick.hide();
800
+ });
801
+ quickpick.onDidHide(() => {
802
+ reject(( new CancellationError()));
803
+ quickpick.hide();
804
+ });
805
+ quickpick.show();
806
+ }));
807
+ if (!continueWithCloudChanges) {
808
+ this.telemetryService.publicLog2('continueOn.editSessions.canStore.outcome', { outcome: 'didNotEnableEditSessionsWhenPrompted' });
809
+ return continueWithCloudChanges;
810
+ }
811
+ const initialized = await this.editSessionsStorageService.initialize('write');
812
+ if (!initialized) {
813
+ this.telemetryService.publicLog2('continueOn.editSessions.canStore.outcome', { outcome: 'didNotEnableEditSessionsWhenPrompted' });
814
+ }
815
+ return initialized;
816
+ }
817
+ return false;
818
+ }
819
+ registerContributedEditSessionOptions() {
820
+ continueEditSessionExtPoint.setHandler(extensions => {
821
+ const continueEditSessionOptions = [];
822
+ for (const extension of extensions) {
823
+ if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) {
824
+ continue;
825
+ }
826
+ if (!Array.isArray(extension.value)) {
827
+ continue;
828
+ }
829
+ for (const contribution of extension.value) {
830
+ const command = MenuRegistry.getCommand(contribution.command);
831
+ if (!command) {
832
+ return;
833
+ }
834
+ const icon = command.icon;
835
+ const title = typeof command.title === 'string' ? command.title : command.title.value;
836
+ const when = ContextKeyExpr.deserialize(contribution.when);
837
+ continueEditSessionOptions.push(( new ContinueEditSessionItem(
838
+ ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title,
839
+ command.id,
840
+ command.source?.title,
841
+ when,
842
+ contribution.documentation
843
+ )));
844
+ if (contribution.qualifiedName) {
845
+ this.generateStandaloneOptionCommand(command.id, contribution.qualifiedName, contribution.category ?? command.category, when, contribution.remoteGroup);
846
+ }
847
+ }
848
+ }
849
+ this.continueEditSessionOptions = continueEditSessionOptions;
850
+ });
851
+ }
852
+ generateStandaloneOptionCommand(commandId, qualifiedName, category, when, remoteGroup) {
853
+ const command = {
854
+ id: `${continueWorkingOnCommand.id}.${commandId}`,
855
+ title: { original: qualifiedName, value: qualifiedName },
856
+ category: typeof category === 'string' ? { original: category, value: category } : category,
857
+ precondition: when,
858
+ f1: true
859
+ };
860
+ if (!( this.registeredCommands.has(command.id))) {
861
+ this.registeredCommands.add(command.id);
862
+ registerAction2(class StandaloneContinueOnOption extends Action2 {
863
+ constructor() {
864
+ super(command);
865
+ }
866
+ async run(accessor) {
867
+ return accessor.get(ICommandService).executeCommand(continueWorkingOnCommand.id, undefined, commandId);
868
+ }
869
+ });
870
+ if (remoteGroup !== undefined) {
871
+ MenuRegistry.appendMenuItem(MenuId.StatusBarRemoteIndicatorMenu, {
872
+ group: remoteGroup,
873
+ command: command,
874
+ when: command.precondition
875
+ });
876
+ }
877
+ }
878
+ }
879
+ registerContinueInLocalFolderAction() {
880
+ const that = this;
881
+ this._register(registerAction2(class ContinueInLocalFolderAction extends Action2 {
882
+ constructor() {
883
+ super(openLocalFolderCommand);
884
+ }
885
+ async run(accessor) {
886
+ const selection = await that.fileDialogService.showOpenDialog({
887
+ title: ( localizeWithPath(
888
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
889
+ 'continueEditSession.openLocalFolder.title.v2',
890
+ 'Select a local folder to continue working in'
891
+ )),
892
+ canSelectFolders: true,
893
+ canSelectMany: false,
894
+ canSelectFiles: false,
895
+ availableFileSystems: [Schemas.file]
896
+ });
897
+ return selection?.length !== 1 ? undefined : ( URI.from({
898
+ scheme: that.productService.urlProtocol,
899
+ authority: Schemas.file,
900
+ path: selection[0].path
901
+ }));
902
+ }
903
+ }));
904
+ if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) {
905
+ this.generateStandaloneOptionCommand(openLocalFolderCommand.id, ( localizeWithPath(
906
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
907
+ 'continueWorkingOn.existingLocalFolder',
908
+ 'Continue Working in Existing Local Folder'
909
+ )), undefined, openLocalFolderCommand.precondition, undefined);
910
+ }
911
+ }
912
+ async pickContinueEditSessionDestination() {
913
+ const quickPick = this.quickInputService.createQuickPick();
914
+ const workspaceContext = this.contextService.getWorkbenchState() === 2
915
+ ? this.contextService.getWorkspace().folders[0].name
916
+ : ( this.contextService.getWorkspace().folders.map((folder) => folder.name)).join(', ');
917
+ quickPick.placeholder = ( localizeWithPath(
918
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
919
+ 'continueEditSessionPick.title.v2',
920
+ "Select a development environment to continue working on {0} in",
921
+ `'${workspaceContext}'`
922
+ ));
923
+ quickPick.items = this.createPickItems();
924
+ this.extensionService.onDidChangeExtensions(() => {
925
+ quickPick.items = this.createPickItems();
926
+ });
927
+ const command = await ( new Promise((resolve, reject) => {
928
+ quickPick.onDidHide(() => resolve(undefined));
929
+ quickPick.onDidAccept((e) => {
930
+ const selection = quickPick.activeItems[0].command;
931
+ if (selection === installAdditionalContinueOnOptionsCommand.id) {
932
+ void this.commandService.executeCommand(installAdditionalContinueOnOptionsCommand.id);
933
+ }
934
+ else {
935
+ resolve(selection);
936
+ quickPick.hide();
937
+ }
938
+ });
939
+ quickPick.show();
940
+ quickPick.onDidTriggerItemButton(async (e) => {
941
+ if (e.item.documentation !== undefined) {
942
+ const uri = URI.isUri(e.item.documentation) ? ( URI.parse(e.item.documentation)) : await this.commandService.executeCommand(e.item.documentation);
943
+ void this.openerService.open(uri, { openExternal: true });
944
+ }
945
+ });
946
+ }));
947
+ quickPick.dispose();
948
+ return command;
949
+ }
950
+ async resolveDestination(command) {
951
+ try {
952
+ const uri = await this.commandService.executeCommand(command);
953
+ if (uri === undefined) {
954
+ this.telemetryService.publicLog2('continueOn.openDestination.outcome', { selection: command, outcome: 'noDestinationUri' });
955
+ return 'noDestinationUri';
956
+ }
957
+ if (URI.isUri(uri)) {
958
+ this.telemetryService.publicLog2('continueOn.openDestination.outcome', { selection: command, outcome: 'resolvedUri' });
959
+ return uri;
960
+ }
961
+ this.telemetryService.publicLog2('continueOn.openDestination.outcome', { selection: command, outcome: 'invalidDestination' });
962
+ return undefined;
963
+ }
964
+ catch (ex) {
965
+ if (ex instanceof CancellationError) {
966
+ this.telemetryService.publicLog2('continueOn.openDestination.outcome', { selection: command, outcome: 'cancelled' });
967
+ }
968
+ else {
969
+ this.telemetryService.publicLog2('continueOn.openDestination.outcome', { selection: command, outcome: 'unknownError' });
970
+ }
971
+ return undefined;
972
+ }
973
+ }
974
+ createPickItems() {
975
+ const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when));
976
+ if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) {
977
+ items.push(( new ContinueEditSessionItem('$(folder) ' + ( localizeWithPath(
978
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
979
+ 'continueEditSessionItem.openInLocalFolder.v2',
980
+ 'Open in Local Folder'
981
+ )), openLocalFolderCommand.id, ( localizeWithPath(
982
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
983
+ 'continueEditSessionItem.builtin',
984
+ 'Built-in'
985
+ )))));
986
+ }
987
+ const sortedItems = items.sort((item1, item2) => item1.label.localeCompare(item2.label));
988
+ return sortedItems.concat({ type: 'separator' }, ( new ContinueEditSessionItem(
989
+ installAdditionalContinueOnOptionsCommand.title,
990
+ installAdditionalContinueOnOptionsCommand.id
991
+ )));
992
+ }
993
+ };
994
+ EditSessionsContribution = EditSessionsContribution_1 = ( __decorate([
995
+ ( __param(0, IEditSessionsStorageService)),
996
+ ( __param(1, IFileService)),
997
+ ( __param(2, IProgressService)),
998
+ ( __param(3, IOpenerService)),
999
+ ( __param(4, ITelemetryService)),
1000
+ ( __param(5, ISCMService)),
1001
+ ( __param(6, INotificationService)),
1002
+ ( __param(7, IDialogService)),
1003
+ ( __param(8, IEditSessionsLogService)),
1004
+ ( __param(9, IEnvironmentService)),
1005
+ ( __param(10, IInstantiationService)),
1006
+ ( __param(11, IProductService)),
1007
+ ( __param(12, IConfigurationService)),
1008
+ ( __param(13, IWorkspaceContextService)),
1009
+ ( __param(14, IEditSessionIdentityService)),
1010
+ ( __param(15, IQuickInputService)),
1011
+ ( __param(16, ICommandService)),
1012
+ ( __param(17, IContextKeyService)),
1013
+ ( __param(18, IFileDialogService)),
1014
+ ( __param(19, ILifecycleService)),
1015
+ ( __param(20, IStorageService)),
1016
+ ( __param(21, IActivityService)),
1017
+ ( __param(22, IEditorService)),
1018
+ ( __param(23, IRemoteAgentService)),
1019
+ ( __param(24, IExtensionService)),
1020
+ ( __param(25, IRequestService)),
1021
+ ( __param(26, IUserDataProfilesService)),
1022
+ ( __param(27, IUriIdentityService)),
1023
+ ( __param(28, IWorkspaceIdentityService))
1024
+ ], EditSessionsContribution));
1025
+ const infoButtonClass = ThemeIcon.asClassName(Codicon.info);
1026
+ class ContinueEditSessionItem {
1027
+ constructor(label, command, description, when, documentation) {
1028
+ this.label = label;
1029
+ this.command = command;
1030
+ this.description = description;
1031
+ this.when = when;
1032
+ this.documentation = documentation;
1033
+ if (documentation !== undefined) {
1034
+ this.buttons = [{
1035
+ iconClass: infoButtonClass,
1036
+ tooltip: ( localizeWithPath(
1037
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1038
+ 'learnMoreTooltip',
1039
+ 'Learn More'
1040
+ )),
1041
+ }];
1042
+ }
1043
+ }
1044
+ }
1045
+ const continueEditSessionExtPoint = ( ExtensionsRegistry.registerExtensionPoint({
1046
+ extensionPoint: 'continueEditSession',
1047
+ jsonSchema: {
1048
+ description: ( localizeWithPath(
1049
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1050
+ 'continueEditSessionExtPoint',
1051
+ 'Contributes options for continuing the current edit session in a different environment'
1052
+ )),
1053
+ type: 'array',
1054
+ items: {
1055
+ type: 'object',
1056
+ properties: {
1057
+ command: {
1058
+ description: ( localizeWithPath(
1059
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1060
+ 'continueEditSessionExtPoint.command',
1061
+ 'Identifier of the command to execute. The command must be declared in the \'commands\'-section and return a URI representing a different environment where the current edit session can be continued.'
1062
+ )),
1063
+ type: 'string'
1064
+ },
1065
+ group: {
1066
+ description: ( localizeWithPath(
1067
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1068
+ 'continueEditSessionExtPoint.group',
1069
+ 'Group into which this item belongs.'
1070
+ )),
1071
+ type: 'string'
1072
+ },
1073
+ qualifiedName: {
1074
+ description: ( localizeWithPath(
1075
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1076
+ 'continueEditSessionExtPoint.qualifiedName',
1077
+ 'A fully qualified name for this item which is used for display in menus.'
1078
+ )),
1079
+ type: 'string'
1080
+ },
1081
+ description: {
1082
+ description: ( localizeWithPath(
1083
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1084
+ 'continueEditSessionExtPoint.description',
1085
+ "The url, or a command that returns the url, to the option's documentation page."
1086
+ )),
1087
+ type: 'string'
1088
+ },
1089
+ remoteGroup: {
1090
+ description: ( localizeWithPath(
1091
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1092
+ 'continueEditSessionExtPoint.remoteGroup',
1093
+ 'Group into which this item belongs in the remote indicator.'
1094
+ )),
1095
+ type: 'string'
1096
+ },
1097
+ when: {
1098
+ description: ( localizeWithPath(
1099
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1100
+ 'continueEditSessionExtPoint.when',
1101
+ 'Condition which must be true to show this item.'
1102
+ )),
1103
+ type: 'string'
1104
+ }
1105
+ },
1106
+ required: ['command']
1107
+ }
1108
+ }
1109
+ }));
1110
+ const workbenchRegistry = ( Registry.as(Extensions$1.Workbench));
1111
+ workbenchRegistry.registerWorkbenchContribution(EditSessionsContribution, 3 );
1112
+ ( Registry.as(Extensions$2.Configuration)).registerConfiguration({
1113
+ ...workbenchConfigurationNodeBase,
1114
+ 'properties': {
1115
+ 'workbench.experimental.cloudChanges.autoStore': {
1116
+ enum: ['onShutdown', 'off'],
1117
+ enumDescriptions: [
1118
+ ( localizeWithPath(
1119
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1120
+ 'autoStoreWorkingChanges.onShutdown',
1121
+ "Automatically store current working changes in the cloud on window close."
1122
+ )),
1123
+ ( localizeWithPath(
1124
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1125
+ 'autoStoreWorkingChanges.off',
1126
+ "Never attempt to automatically store working changes in the cloud."
1127
+ ))
1128
+ ],
1129
+ 'type': 'string',
1130
+ 'tags': ['experimental', 'usesOnlineServices'],
1131
+ 'default': 'off',
1132
+ 'markdownDescription': ( localizeWithPath(
1133
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1134
+ 'autoStoreWorkingChangesDescription',
1135
+ "Controls whether to automatically store available working changes in the cloud for the current workspace. This setting has no effect in the web."
1136
+ )),
1137
+ },
1138
+ 'workbench.cloudChanges.autoResume': {
1139
+ enum: ['onReload', 'off'],
1140
+ enumDescriptions: [
1141
+ ( localizeWithPath(
1142
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1143
+ 'autoResumeWorkingChanges.onReload',
1144
+ "Automatically resume available working changes from the cloud on window reload."
1145
+ )),
1146
+ ( localizeWithPath(
1147
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1148
+ 'autoResumeWorkingChanges.off',
1149
+ "Never attempt to resume working changes from the cloud."
1150
+ ))
1151
+ ],
1152
+ 'type': 'string',
1153
+ 'tags': ['usesOnlineServices'],
1154
+ 'default': 'onReload',
1155
+ 'markdownDescription': ( localizeWithPath(
1156
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1157
+ 'autoResumeWorkingChanges',
1158
+ "Controls whether to automatically resume available working changes stored in the cloud for the current workspace."
1159
+ )),
1160
+ },
1161
+ 'workbench.cloudChanges.continueOn': {
1162
+ enum: ['prompt', 'off'],
1163
+ enumDescriptions: [
1164
+ ( localizeWithPath(
1165
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1166
+ 'continueOnCloudChanges.promptForAuth',
1167
+ 'Prompt the user to sign in to store working changes in the cloud with Continue Working On.'
1168
+ )),
1169
+ ( localizeWithPath(
1170
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1171
+ 'continueOnCloudChanges.off',
1172
+ 'Do not store working changes in the cloud with Continue Working On unless the user has already turned on Cloud Changes.'
1173
+ ))
1174
+ ],
1175
+ type: 'string',
1176
+ tags: ['usesOnlineServices'],
1177
+ default: 'prompt',
1178
+ markdownDescription: ( localizeWithPath(
1179
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1180
+ 'continueOnCloudChanges',
1181
+ 'Controls whether to prompt the user to store working changes in the cloud when using Continue Working On.'
1182
+ ))
1183
+ },
1184
+ 'workbench.experimental.cloudChanges.partialMatches.enabled': {
1185
+ 'type': 'boolean',
1186
+ 'tags': ['experimental', 'usesOnlineServices'],
1187
+ 'default': false,
1188
+ 'markdownDescription': ( localizeWithPath(
1189
+ 'vs/workbench/contrib/editSessions/browser/editSessions.contribution',
1190
+ 'cloudChangesPartialMatchesEnabled',
1191
+ "Controls whether to surface cloud changes which partially match the current session."
1192
+ ))
1193
+ }
1194
+ }
1195
+ });
1196
+
1197
+ export { EditSessionsContribution };