Path: blob/main/src/vs/workbench/api/browser/mainThreadCommands.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { DisposableMap, IDisposable } from '../../../base/common/lifecycle.js';6import { revive } from '../../../base/common/marshalling.js';7import { CommandsRegistry, ICommandMetadata, ICommandService } from '../../../platform/commands/common/commands.js';8import { IExtHostContext, extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js';9import { IExtensionService } from '../../services/extensions/common/extensions.js';10import { Dto, SerializableObjectWithBuffers } from '../../services/extensions/common/proxyIdentifier.js';11import { ExtHostCommandsShape, ExtHostContext, MainContext, MainThreadCommandsShape } from '../common/extHost.protocol.js';12import { isString } from '../../../base/common/types.js';131415@extHostNamedCustomer(MainContext.MainThreadCommands)16export class MainThreadCommands implements MainThreadCommandsShape {1718private readonly _commandRegistrations = new DisposableMap<string>();19private readonly _generateCommandsDocumentationRegistration: IDisposable;20private readonly _proxy: ExtHostCommandsShape;2122constructor(23extHostContext: IExtHostContext,24@ICommandService private readonly _commandService: ICommandService,25@IExtensionService private readonly _extensionService: IExtensionService,26) {27this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostCommands);2829this._generateCommandsDocumentationRegistration = CommandsRegistry.registerCommand('_generateCommandsDocumentation', () => this._generateCommandsDocumentation());30}3132dispose() {33this._commandRegistrations.dispose();34this._generateCommandsDocumentationRegistration.dispose();35}3637private async _generateCommandsDocumentation(): Promise<void> {38const result = await this._proxy.$getContributedCommandMetadata();3940// add local commands41const commands = CommandsRegistry.getCommands();42for (const [id, command] of commands) {43if (command.metadata) {44result[id] = command.metadata;45}46}4748// print all as markdown49const all: string[] = [];50for (const id in result) {51all.push('`' + id + '` - ' + _generateMarkdown(result[id]));52}53console.log(all.join('\n'));54}5556$registerCommand(id: string): void {57this._commandRegistrations.set(58id,59CommandsRegistry.registerCommand(id, (accessor, ...args) => {60return this._proxy.$executeContributedCommand(id, ...args).then(result => {61return revive(result);62});63})64);65}6667$unregisterCommand(id: string): void {68this._commandRegistrations.deleteAndDispose(id);69}7071$fireCommandActivationEvent(id: string): void {72const activationEvent = `onCommand:${id}`;73if (!this._extensionService.activationEventIsDone(activationEvent)) {74// this is NOT awaited because we only use it as drive-by-activation75// for commands that are already known inside the extension host76this._extensionService.activateByEvent(activationEvent);77}78}7980async $executeCommand<T>(id: string, args: any[] | SerializableObjectWithBuffers<any[]>, retry: boolean): Promise<T | undefined> {81if (args instanceof SerializableObjectWithBuffers) {82args = args.value;83}84for (let i = 0; i < args.length; i++) {85args[i] = revive(args[i]);86}87if (retry && args.length > 0 && !CommandsRegistry.getCommand(id)) {88await this._extensionService.activateByEvent(`onCommand:${id}`);89throw new Error('$executeCommand:retry');90}91return this._commandService.executeCommand<T>(id, ...args);92}9394$getCommands(): Promise<string[]> {95return Promise.resolve([...CommandsRegistry.getCommands().keys()]);96}97}9899// --- command doc100101function _generateMarkdown(description: string | Dto<ICommandMetadata> | ICommandMetadata): string {102if (typeof description === 'string') {103return description;104} else {105const descriptionString = isString(description.description)106? description.description107// Our docs website is in English, so keep the original here.108: description.description.original;109const parts = [descriptionString];110parts.push('\n\n');111if (description.args) {112for (const arg of description.args) {113parts.push(`* _${arg.name}_ - ${arg.description || ''}\n`);114}115}116if (description.returns) {117parts.push(`* _(returns)_ - ${description.returns}`);118}119parts.push('\n\n');120return parts.join('');121}122}123124125