Files
code-server/lib/vscode/src/vs/workbench/api/common/apiCommands.ts
2021-02-09 16:08:37 +00:00

210 lines
8.0 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI, UriComponents } from 'vs/base/common/uri';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { IWorkspacesService, IRecent } from 'vs/platform/workspaces/common/workspaces';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IViewDescriptorService, IViewsService, ViewVisibilityState } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
// -----------------------------------------------------------------
// The following commands are registered on both sides separately.
//
// We are trying to maintain backwards compatibility for cases where
// API commands are encoded as markdown links, for example.
// -----------------------------------------------------------------
export interface ICommandsExecutor {
executeCommand<T>(id: string, ...args: any[]): Promise<T | undefined>;
}
function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) => any): ICommandHandler {
return (accessor, ...args: any[]) => {
return handler(accessor.get(ICommandService), ...args);
};
}
interface INewWindowAPICommandOptions {
reuseWindow?: boolean;
remoteAuthority?: string;
}
export class NewWindowAPICommand {
public static readonly ID = 'vscode.newWindow';
public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise<any> {
const commandOptions: IOpenEmptyWindowOptions = {
forceReuseWindow: options && options.reuseWindow,
remoteAuthority: options && options.remoteAuthority
};
return executor.executeCommand('_files.newWindow', commandOptions);
}
}
CommandsRegistry.registerCommand({
id: NewWindowAPICommand.ID,
handler: adjustHandler(NewWindowAPICommand.execute),
description: {
description: 'Opens an new window',
args: [
]
}
});
CommandsRegistry.registerCommand('_workbench.removeFromRecentlyOpened', function (accessor: ServicesAccessor, uri: URI) {
const workspacesService = accessor.get(IWorkspacesService);
return workspacesService.removeRecentlyOpened([uri]);
});
export class RemoveFromRecentlyOpenedAPICommand {
public static readonly ID = 'vscode.removeFromRecentlyOpened';
public static execute(executor: ICommandsExecutor, path: string | URI): Promise<any> {
if (typeof path === 'string') {
path = path.match(/^[^:/?#]+:\/\//) ? URI.parse(path) : URI.file(path);
} else {
path = URI.revive(path); // called from extension host
}
return executor.executeCommand('_workbench.removeFromRecentlyOpened', path);
}
}
CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute));
export interface OpenIssueReporterArgs {
readonly extensionId: string;
readonly issueTitle?: string;
readonly issueBody?: string;
}
export class OpenIssueReporter {
public static readonly ID = 'vscode.openIssueReporter';
public static execute(executor: ICommandsExecutor, args: string | OpenIssueReporterArgs): Promise<void> {
const commandArgs = typeof args === 'string'
? { extensionId: args }
: args;
return executor.executeCommand('workbench.action.openIssueReporter', commandArgs);
}
}
interface RecentEntry {
uri: URI;
type: 'workspace' | 'folder' | 'file';
label?: string;
}
CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) {
const workspacesService = accessor.get(IWorkspacesService);
let recent: IRecent | undefined = undefined;
const uri = recentEntry.uri;
const label = recentEntry.label;
if (recentEntry.type === 'workspace') {
const workspace = await workspacesService.getWorkspaceIdentifier(uri);
recent = { workspace, label };
} else if (recentEntry.type === 'folder') {
recent = { folderUri: uri, label };
} else {
recent = { fileUri: uri, label };
}
return workspacesService.addRecentlyOpened([recent]);
});
CommandsRegistry.registerCommand('_workbench.getRecentlyOpened', async function (accessor: ServicesAccessor) {
const workspacesService = accessor.get(IWorkspacesService);
return workspacesService.getRecentlyOpened();
});
CommandsRegistry.registerCommand('_extensionTests.setLogLevel', function (accessor: ServicesAccessor, level: number) {
const logService = accessor.get(ILogService);
const environmentService = accessor.get(IEnvironmentService);
if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) {
logService.setLevel(level);
}
});
CommandsRegistry.registerCommand('_workbench.openExternal', function (accessor: ServicesAccessor, uri: UriComponents, options: { allowTunneling?: boolean }) {
// TODO: discuss martin, ben where to put this
const openerService = accessor.get(IOpenerService);
openerService.open(URI.revive(uri), options);
});
CommandsRegistry.registerCommand('_extensionTests.getLogLevel', function (accessor: ServicesAccessor) {
const logService = accessor.get(ILogService);
return logService.getLevel();
});
CommandsRegistry.registerCommand('_workbench.action.moveViews', async function (accessor: ServicesAccessor, options: { viewIds: string[], destinationId: string }) {
const viewDescriptorService = accessor.get(IViewDescriptorService);
const destination = viewDescriptorService.getViewContainerById(options.destinationId);
if (!destination) {
return;
}
// FYI, don't use `moveViewsToContainer` in 1 shot, because it expects all views to have the same current location
for (const viewId of options.viewIds) {
const viewDescriptor = viewDescriptorService.getViewDescriptorById(viewId);
if (viewDescriptor?.canMoveView) {
viewDescriptorService.moveViewsToContainer([viewDescriptor], destination, ViewVisibilityState.Default);
}
}
await accessor.get(IViewsService).openViewContainer(destination.id, true);
});
export class MoveViewsAPICommand {
public static readonly ID = 'vscode.moveViews';
public static execute(executor: ICommandsExecutor, options: { viewIds: string[], destinationId: string }): Promise<any> {
if (!Array.isArray(options?.viewIds) || typeof options?.destinationId !== 'string') {
return Promise.reject('Invalid arguments');
}
return executor.executeCommand('_workbench.action.moveViews', options);
}
}
CommandsRegistry.registerCommand({
id: MoveViewsAPICommand.ID,
handler: adjustHandler(MoveViewsAPICommand.execute),
description: {
description: 'Move Views',
args: []
}
});
// -----------------------------------------------------------------
// The following commands are registered on the renderer but as API
// command. DO NOT USE this unless you have understood what this
// means
// -----------------------------------------------------------------
class OpenAPICommand {
public static readonly ID = 'vscode.open';
public static execute(executor: ICommandsExecutor, resource: URI): Promise<any> {
return executor.executeCommand('_workbench.open', resource);
}
}
CommandsRegistry.registerCommand(OpenAPICommand.ID, adjustHandler(OpenAPICommand.execute));
class DiffAPICommand {
public static readonly ID = 'vscode.diff';
public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: typeConverters.TextEditorOpenOptions): Promise<any> {
return executor.executeCommand('_workbench.diff', [
left, right,
label,
]);
}
}
CommandsRegistry.registerCommand(DiffAPICommand.ID, adjustHandler(DiffAPICommand.execute));