mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 13:29:44 +00:00
This reverts commit a8fe1cc157
.
This commit is contained in:
parent
f4c58486f4
commit
645c718a99
|
@ -1,160 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const IContinueOnPicker = createDecorator<IContinueOnPicker>('IContinueOnPicker');
|
||||
export interface IContinueOnPicker {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
pick(): Promise<URI | 'noDestinationUri' | undefined>;
|
||||
}
|
||||
|
||||
export class ContinueOnPicker extends Disposable implements IContinueOnPicker {
|
||||
_serviceBrand = undefined;
|
||||
|
||||
private continueEditSessionOptions: ContinueEditSessionItem[] = [];
|
||||
|
||||
constructor(
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.registerContributedEditSessionOptions();
|
||||
}
|
||||
|
||||
private registerContributedEditSessionOptions() {
|
||||
continueEditSessionExtPoint.setHandler(extensions => {
|
||||
const continueEditSessionOptions: ContinueEditSessionItem[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) {
|
||||
continue;
|
||||
}
|
||||
if (!Array.isArray(extension.value)) {
|
||||
continue;
|
||||
}
|
||||
for (const contribution of extension.value) {
|
||||
const command = MenuRegistry.getCommand(contribution.command);
|
||||
if (!command) {
|
||||
return;
|
||||
}
|
||||
|
||||
const icon = command.icon;
|
||||
const title = typeof command.title === 'string' ? command.title : command.title.value;
|
||||
|
||||
continueEditSessionOptions.push(new ContinueEditSessionItem(
|
||||
ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title,
|
||||
command.id,
|
||||
command.source,
|
||||
ContextKeyExpr.deserialize(contribution.when)
|
||||
));
|
||||
}
|
||||
}
|
||||
this.continueEditSessionOptions = continueEditSessionOptions;
|
||||
});
|
||||
}
|
||||
|
||||
async pick(): Promise<URI | 'noDestinationUri' | undefined> {
|
||||
const quickPick = this.quickInputService.createQuickPick<ContinueEditSessionItem>();
|
||||
|
||||
const workspaceContext = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER
|
||||
? this.contextService.getWorkspace().folders[0].name
|
||||
: this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', ');
|
||||
quickPick.title = localize('continueEditSessionPick.title', "Continue {0} on", `'${workspaceContext}'`);
|
||||
quickPick.placeholder = localize('continueEditSessionPick.placeholder', 'Choose how you would like to continue working');
|
||||
quickPick.items = this.createPickItems();
|
||||
|
||||
const command = await new Promise<string | undefined>((resolve, reject) => {
|
||||
quickPick.onDidHide(() => resolve(undefined));
|
||||
|
||||
quickPick.onDidAccept((e) => {
|
||||
const selection = quickPick.activeItems[0].command;
|
||||
resolve(selection);
|
||||
quickPick.hide();
|
||||
});
|
||||
|
||||
quickPick.show();
|
||||
});
|
||||
|
||||
quickPick.dispose();
|
||||
|
||||
if (command === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const uri = await this.commandService.executeCommand(command);
|
||||
|
||||
// Some continue on commands do not return a URI
|
||||
// to support extensions which want to be in control
|
||||
// of how the destination is opened
|
||||
if (uri === undefined) { return 'noDestinationUri'; }
|
||||
|
||||
return URI.isUri(uri) ? uri : undefined;
|
||||
} catch (ex) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private createPickItems(): ContinueEditSessionItem[] {
|
||||
const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when));
|
||||
return items.sort((item1, item2) => item1.label.localeCompare(item2.label));
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueEditSessionItem implements IQuickPickItem {
|
||||
constructor(
|
||||
public readonly label: string,
|
||||
public readonly command: string,
|
||||
public readonly description?: string,
|
||||
public readonly when?: ContextKeyExpression,
|
||||
) { }
|
||||
}
|
||||
|
||||
interface ICommand {
|
||||
command: string;
|
||||
group: string;
|
||||
when: string;
|
||||
}
|
||||
|
||||
const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint<ICommand[]>({
|
||||
extensionPoint: 'continueEditSession',
|
||||
jsonSchema: {
|
||||
description: localize('continueEditSessionExtPoint', 'Contributes options for continuing the current edit session in a different environment'),
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
command: {
|
||||
description: localize('continueEditSessionExtPoint.command', '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.'),
|
||||
type: 'string'
|
||||
},
|
||||
group: {
|
||||
description: localize('continueEditSessionExtPoint.group', 'Group into which this item belongs.'),
|
||||
type: 'string'
|
||||
},
|
||||
when: {
|
||||
description: localize('continueEditSessionExtPoint.when', 'Condition which must be true to show this item.'),
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['command']
|
||||
}
|
||||
}
|
||||
});
|
|
@ -7,7 +7,7 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
|||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { Action2, IAction2Options, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IEditSessionsStorageService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EDIT_SESSIONS_CONTAINER_ID, EditSessionSchemaVersion, IEditSessionsLogService, EDIT_SESSIONS_VIEW_ICON, EDIT_SESSIONS_TITLE, EDIT_SESSIONS_SHOW_VIEW, EDIT_SESSIONS_DATA_VIEW_ID, decodeEditSessionFileContent } from 'vs/workbench/contrib/editSessions/common/editSessions';
|
||||
|
@ -20,17 +20,24 @@ import { encodeBase64 } from 'vs/base/common/buffer';
|
|||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { EditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/browser/editSessionsStorageService';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { getFileNamesMessage, IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { getFileNamesMessage, IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
|
||||
import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ContextKeyExpr, ContextKeyExpression, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtualWorkspace';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { EditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessionsLogService';
|
||||
import { IViewContainersRegistry, Extensions as ViewExtensions, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
|
@ -38,20 +45,20 @@ import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneCont
|
|||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { EditSessionsDataViews } from 'vs/workbench/contrib/editSessions/browser/editSessionsViews';
|
||||
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 { equals } from 'vs/base/common/objects';
|
||||
import { IEditSessionIdentityService } from 'vs/platform/workspace/common/editSessions';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { IOutputService } from 'vs/workbench/services/output/common/output';
|
||||
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
|
||||
import { sha1Hex } from 'vs/base/browser/hash';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { ContinueOnPicker, IContinueOnPicker } from 'vs/workbench/contrib/editSessions/browser/continueOnPicker';
|
||||
|
||||
registerSingleton(IEditSessionsLogService, EditSessionsLogService, false);
|
||||
registerSingleton(IEditSessionsStorageService, EditSessionsWorkbenchService, false);
|
||||
registerSingleton(IContinueOnPicker, ContinueOnPicker, InstantiationType.Delayed);
|
||||
|
||||
const continueWorkingOnCommand: IAction2Options = {
|
||||
id: '_workbench.editSessions.actions.continueEditSession',
|
||||
|
@ -59,6 +66,12 @@ const continueWorkingOnCommand: IAction2Options = {
|
|||
precondition: WorkspaceFolderCountContext.notEqualsTo('0'),
|
||||
f1: true
|
||||
};
|
||||
const openLocalFolderCommand: IAction2Options = {
|
||||
id: '_workbench.editSessions.actions.continueEditSession.openLocalFolder',
|
||||
title: { value: localize('continue edit session in local folder', "Open In Local Folder"), original: 'Open In Local Folder' },
|
||||
category: EDIT_SESSION_SYNC_CATEGORY,
|
||||
precondition: IsWebContext
|
||||
};
|
||||
const showOutputChannelCommand: IAction2Options = {
|
||||
id: 'workbench.editSessions.actions.showOutputChannel',
|
||||
title: { value: localize('show log', 'Show Log'), original: 'Show Log' },
|
||||
|
@ -73,6 +86,9 @@ const queryParamName = 'editSessionId';
|
|||
|
||||
const useEditSessionsWithContinueOn = 'workbench.editSessions.continueOn';
|
||||
export class EditSessionsContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private continueEditSessionOptions: ContinueEditSessionItem[] = [];
|
||||
|
||||
private readonly shouldShowViewsContext: IContextKey<boolean>;
|
||||
|
||||
private static APPLICATION_LAUNCHED_VIA_CONTINUE_ON_STORAGE_KEY = 'applicationLaunchedViaContinueOn';
|
||||
|
@ -94,11 +110,13 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
|
|||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
|
||||
@IEditSessionIdentityService private readonly editSessionIdentityService: IEditSessionIdentityService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IActivityService private readonly activityService: IActivityService,
|
||||
@IContinueOnPicker private readonly continueOnPicker: IContinueOnPicker,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -106,6 +124,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
|
|||
|
||||
this.registerActions();
|
||||
this.registerViews();
|
||||
this.registerContributedEditSessionOptions();
|
||||
|
||||
this.shouldShowViewsContext = EDIT_SESSIONS_SHOW_VIEW.bindTo(this.contextKeyService);
|
||||
|
||||
|
@ -218,6 +237,8 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
|
|||
this.registerResumeLatestEditSessionAction();
|
||||
this.registerStoreLatestEditSessionAction();
|
||||
|
||||
this.registerContinueInLocalFolderAction();
|
||||
|
||||
this.registerShowEditSessionViewAction();
|
||||
this.registerShowEditSessionOutputChannelAction();
|
||||
}
|
||||
|
@ -271,7 +292,7 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
|
|||
|
||||
const shouldStoreEditSession = await that.shouldContinueOnWithEditSession();
|
||||
|
||||
let uri = workspaceUri ?? await that.continueOnPicker.pick();
|
||||
let uri = workspaceUri ?? await that.pickContinueEditSessionDestination();
|
||||
if (uri === undefined) { return; }
|
||||
|
||||
// Run the store action to get back a ref
|
||||
|
@ -627,8 +648,162 @@ export class EditSessionsContribution extends Disposable implements IWorkbenchCo
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
//#region Continue Edit Session extension contribution point
|
||||
|
||||
private registerContributedEditSessionOptions() {
|
||||
continueEditSessionExtPoint.setHandler(extensions => {
|
||||
const continueEditSessionOptions: ContinueEditSessionItem[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (!isProposedApiEnabled(extension.description, 'contribEditSessions')) {
|
||||
continue;
|
||||
}
|
||||
if (!Array.isArray(extension.value)) {
|
||||
continue;
|
||||
}
|
||||
for (const contribution of extension.value) {
|
||||
const command = MenuRegistry.getCommand(contribution.command);
|
||||
if (!command) {
|
||||
return;
|
||||
}
|
||||
|
||||
const icon = command.icon;
|
||||
const title = typeof command.title === 'string' ? command.title : command.title.value;
|
||||
|
||||
continueEditSessionOptions.push(new ContinueEditSessionItem(
|
||||
ThemeIcon.isThemeIcon(icon) ? `$(${icon.id}) ${title}` : title,
|
||||
command.id,
|
||||
command.source,
|
||||
ContextKeyExpr.deserialize(contribution.when)
|
||||
));
|
||||
}
|
||||
}
|
||||
this.continueEditSessionOptions = continueEditSessionOptions;
|
||||
});
|
||||
}
|
||||
|
||||
private registerContinueInLocalFolderAction(): void {
|
||||
const that = this;
|
||||
this._register(registerAction2(class ContinueInLocalFolderAction extends Action2 {
|
||||
constructor() {
|
||||
super(openLocalFolderCommand);
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<URI | undefined> {
|
||||
const selection = await that.fileDialogService.showOpenDialog({
|
||||
title: localize('continueEditSession.openLocalFolder.title', 'Select a local folder to continue your edit session in'),
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
canSelectFiles: false,
|
||||
availableFileSystems: [Schemas.file]
|
||||
});
|
||||
|
||||
return selection?.length !== 1 ? undefined : URI.from({
|
||||
scheme: that.productService.urlProtocol,
|
||||
authority: Schemas.file,
|
||||
path: selection[0].path
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private async pickContinueEditSessionDestination(): Promise<URI | 'noDestinationUri' | undefined> {
|
||||
const quickPick = this.quickInputService.createQuickPick<ContinueEditSessionItem>();
|
||||
|
||||
const workspaceContext = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER
|
||||
? this.contextService.getWorkspace().folders[0].name
|
||||
: this.contextService.getWorkspace().folders.map((folder) => folder.name).join(', ');
|
||||
quickPick.title = localize('continueEditSessionPick.title', "Continue {0} on", `'${workspaceContext}'`);
|
||||
quickPick.placeholder = localize('continueEditSessionPick.placeholder', 'Choose how you would like to continue working');
|
||||
quickPick.items = this.createPickItems();
|
||||
|
||||
const command = await new Promise<string | undefined>((resolve, reject) => {
|
||||
quickPick.onDidHide(() => resolve(undefined));
|
||||
|
||||
quickPick.onDidAccept((e) => {
|
||||
const selection = quickPick.activeItems[0].command;
|
||||
resolve(selection);
|
||||
quickPick.hide();
|
||||
});
|
||||
|
||||
quickPick.show();
|
||||
});
|
||||
|
||||
quickPick.dispose();
|
||||
|
||||
if (command === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const uri = await this.commandService.executeCommand(command);
|
||||
|
||||
// Some continue on commands do not return a URI
|
||||
// to support extensions which want to be in control
|
||||
// of how the destination is opened
|
||||
if (uri === undefined) { return 'noDestinationUri'; }
|
||||
|
||||
return URI.isUri(uri) ? uri : undefined;
|
||||
} catch (ex) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private createPickItems(): ContinueEditSessionItem[] {
|
||||
const items = [...this.continueEditSessionOptions].filter((option) => option.when === undefined || this.contextKeyService.contextMatchesRules(option.when));
|
||||
|
||||
if (getVirtualWorkspaceLocation(this.contextService.getWorkspace()) !== undefined && isNative) {
|
||||
items.push(new ContinueEditSessionItem(
|
||||
'$(folder) ' + localize('continueEditSessionItem.openInLocalFolder.v2', 'Open in Local Folder'),
|
||||
openLocalFolderCommand.id,
|
||||
localize('continueEditSessionItem.builtin', 'Built-in')
|
||||
));
|
||||
}
|
||||
|
||||
return items.sort((item1, item2) => item1.label.localeCompare(item2.label));
|
||||
}
|
||||
}
|
||||
|
||||
class ContinueEditSessionItem implements IQuickPickItem {
|
||||
constructor(
|
||||
public readonly label: string,
|
||||
public readonly command: string,
|
||||
public readonly description?: string,
|
||||
public readonly when?: ContextKeyExpression,
|
||||
) { }
|
||||
}
|
||||
|
||||
interface ICommand {
|
||||
command: string;
|
||||
group: string;
|
||||
when: string;
|
||||
}
|
||||
|
||||
const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint<ICommand[]>({
|
||||
extensionPoint: 'continueEditSession',
|
||||
jsonSchema: {
|
||||
description: localize('continueEditSessionExtPoint', 'Contributes options for continuing the current edit session in a different environment'),
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
command: {
|
||||
description: localize('continueEditSessionExtPoint.command', '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.'),
|
||||
type: 'string'
|
||||
},
|
||||
group: {
|
||||
description: localize('continueEditSessionExtPoint.group', 'Group into which this item belongs.'),
|
||||
type: 'string'
|
||||
},
|
||||
when: {
|
||||
description: localize('continueEditSessionExtPoint.when', 'Condition which must be true to show this item.'),
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
required: ['command']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
|
|
Loading…
Reference in a new issue