Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make edit session operations cancellable #166764

Merged
merged 2 commits into from Nov 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/vs/platform/workspace/common/editSessions.ts
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
Expand All @@ -20,8 +20,8 @@ export interface IEditSessionIdentityService {
readonly _serviceBrand: undefined;

registerEditSessionIdentityProvider(provider: IEditSessionIdentityProvider): IDisposable;
getEditSessionIdentifier(workspaceFolder: IWorkspaceFolder, cancellationTokenSource: CancellationTokenSource): Promise<string | undefined>;
provideEditSessionIdentityMatch(workspaceFolder: IWorkspaceFolder, identity1: string, identity2: string, cancellationTokenSource: CancellationTokenSource): Promise<EditSessionIdentityMatch | undefined>;
getEditSessionIdentifier(workspaceFolder: IWorkspaceFolder, cancellationToken: CancellationToken): Promise<string | undefined>;
provideEditSessionIdentityMatch(workspaceFolder: IWorkspaceFolder, identity1: string, identity2: string, cancellationToken: CancellationToken): Promise<EditSessionIdentityMatch | undefined>;
}

export enum EditSessionIdentityMatch {
Expand Down
Expand Up @@ -47,7 +47,7 @@ import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser
import { EditSessionsFileSystemProvider } from 'vs/workbench/contrib/editSessions/browser/editSessionsFileSystemProvider';
import { isNative } from 'vs/base/common/platform';
import { WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { equals } from 'vs/base/common/objects';
import { EditSessionIdentityMatch, IEditSessionIdentityService } from 'vs/platform/workspace/common/editSessions';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
Expand Down Expand Up @@ -209,11 +209,15 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo

private async autoStoreEditSession() {
if (this.configurationService.getValue('workbench.experimental.editSessions.autoStore') === 'onShutdown') {
const cancellationTokenSource = new CancellationTokenSource();
await this.progressService.withProgress({
location: ProgressLocation.Window,
type: 'syncing',
title: localize('store working changes', 'Storing working changes...')
}, async () => this.storeEditSession(false));
}, async () => this.storeEditSession(false, cancellationTokenSource.token), () => {
cancellationTokenSource.cancel();
cancellationTokenSource.dispose();
});
}
}

Expand Down Expand Up @@ -308,11 +312,16 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
// Run the store action to get back a ref
let ref: string | undefined;
if (shouldStoreEditSession) {
const cancellationTokenSource = new CancellationTokenSource();
ref = await that.progressService.withProgress({
location: ProgressLocation.Notification,
cancellable: true,
type: 'syncing',
title: localize('store your working changes', 'Storing your working changes...')
}, async () => that.storeEditSession(false));
}, async () => that.storeEditSession(false, cancellationTokenSource.token), () => {
cancellationTokenSource.cancel();
cancellationTokenSource.dispose();
});
}

// Append the ref to the URI
Expand Down Expand Up @@ -380,6 +389,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
}

async run(accessor: ServicesAccessor): Promise<void> {
const cancellationTokenSource = new CancellationTokenSource();
await that.progressService.withProgress({
location: ProgressLocation.Notification,
title: localize('storing working changes', 'Storing working changes...')
Expand All @@ -390,7 +400,10 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
};
that.telemetryService.publicLog2<StoreEvent, StoreClassification>('editSessions.store');

await that.storeEditSession(true);
await that.storeEditSession(true, cancellationTokenSource.token);
}, () => {
cancellationTokenSource.cancel();
cancellationTokenSource.dispose();
});
}
}));
Expand Down Expand Up @@ -484,7 +497,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
if (folder.canonicalIdentity) {
// Look for an edit session identifier that we can use
for (const f of workspaceFolders) {
const identity = await this.editSessionIdentityService.getEditSessionIdentifier(f, cancellationTokenSource);
const identity = await this.editSessionIdentityService.getEditSessionIdentifier(f, cancellationTokenSource.token);
this.logService.info(`Matching identity ${identity} against edit session folder identity ${folder.canonicalIdentity}...`);

if (equals(identity, folder.canonicalIdentity)) {
Expand All @@ -493,7 +506,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
}

if (identity !== undefined) {
const match = await this.editSessionIdentityService.provideEditSessionIdentityMatch(f, identity, folder.canonicalIdentity, cancellationTokenSource);
const match = await this.editSessionIdentityService.provideEditSessionIdentityMatch(f, identity, folder.canonicalIdentity, cancellationTokenSource.token);
if (match === EditSessionIdentityMatch.Complete) {
folderRoot = f;
break;
Expand Down Expand Up @@ -566,7 +579,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
}
}

async storeEditSession(fromStoreCommand: boolean): Promise<string | undefined> {
async storeEditSession(fromStoreCommand: boolean, cancellationToken: CancellationToken): Promise<string | undefined> {
const folders: Folder[] = [];
let hasEdits = false;

Expand Down Expand Up @@ -612,7 +625,10 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
}
}

const canonicalIdentity = workspaceFolder ? await this.editSessionIdentityService.getEditSessionIdentifier(workspaceFolder, new CancellationTokenSource()) : undefined;
let canonicalIdentity = undefined;
if (workspaceFolder !== null && workspaceFolder !== undefined) {
canonicalIdentity = await this.editSessionIdentityService.getEditSessionIdentifier(workspaceFolder, cancellationToken);
}

folders.push({ workingChanges, name: name ?? '', canonicalIdentity: canonicalIdentity ?? undefined });
}
Expand Down
Expand Up @@ -37,6 +37,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IEditorService, ISaveAllEditorsOptions } from 'vs/workbench/services/editor/common/editorService';
import { CancellationTokenSource } from 'vs/base/common/cancellation';

const folderName = 'test-folder';
const folderUri = URI.file(`/${folderName}`);
Expand Down Expand Up @@ -168,7 +169,7 @@ suite('Edit session sync', () => {
// Create root folder
await fileService.createFolder(folderUri);

await editSessionsContribution.storeEditSession(true);
await editSessionsContribution.storeEditSession(true, new CancellationTokenSource().token);

// Verify that we did not attempt to write the edit session
assert.equal(writeStub.called, false);
Expand Down
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
Expand Down Expand Up @@ -32,22 +32,22 @@ export class EditSessionIdentityService implements IEditSessionIdentityService {
});
}

async getEditSessionIdentifier(workspaceFolder: IWorkspaceFolder, cancellationTokenSource: CancellationTokenSource): Promise<string | undefined> {
async getEditSessionIdentifier(workspaceFolder: IWorkspaceFolder, token: CancellationToken): Promise<string | undefined> {
const { scheme } = workspaceFolder.uri;

const provider = await this.activateProvider(scheme);
this._logService.trace(`EditSessionIdentityProvider for scheme ${scheme} available: ${!!provider}`);

return provider?.getEditSessionIdentifier(workspaceFolder, cancellationTokenSource.token);
return provider?.getEditSessionIdentifier(workspaceFolder, token);
}

async provideEditSessionIdentityMatch(workspaceFolder: IWorkspaceFolder, identity1: string, identity2: string, cancellationTokenSource: CancellationTokenSource): Promise<EditSessionIdentityMatch | undefined> {
async provideEditSessionIdentityMatch(workspaceFolder: IWorkspaceFolder, identity1: string, identity2: string, cancellationToken: CancellationToken): Promise<EditSessionIdentityMatch | undefined> {
const { scheme } = workspaceFolder.uri;

const provider = await this.activateProvider(scheme);
this._logService.trace(`EditSessionIdentityProvider for scheme ${scheme} available: ${!!provider}`);

return provider?.provideEditSessionIdentityMatch?.(workspaceFolder, identity1, identity2, cancellationTokenSource.token);
return provider?.provideEditSessionIdentityMatch?.(workspaceFolder, identity1, identity2, cancellationToken);
}

private async activateProvider(scheme: string) {
Expand Down